mirror of
				https://github.com/SectorLabs/django-localized-fields.git
				synced 2025-10-31 18:48:56 +03:00 
			
		
		
		
	
			
				
					
						
					
					f7c14f897c7c97840b1de0ee66445f8179118ede
				
			
			
		
	django-localized-fields
=======================
.. image:: https://scrutinizer-ci.com/g/SectorLabs/django-localized-fields/badges/quality-score.png
    :target: https://scrutinizer-ci.com/g/SectorLabs/django-localized-fields/
.. image:: https://scrutinizer-ci.com/g/SectorLabs/django-localized-fields/badges/coverage.png
    :target: https://scrutinizer-ci.com/g/SectorLabs/django-localized-fields/
.. image:: https://img.shields.io/github/license/SectorLabs/django-localized-fields.svg
.. image:: https://badge.fury.io/py/django-localized-fields.svg
    :target: https://pypi.python.org/pypi/django-localized-fields
``django-localized-fields`` is an implementation of a field class for Django models that allows the field's value to be set in multiple languages. It does this by utilizing the ``hstore`` type (PostgreSQL specific), which is available as ``models.HStoreField`` in Django 1.10.
This package requires Python 3.5 or newer, Django 1.10 or newer and PostgreSQL 9.6 or newer.
Installation
------------
1. Install the package from PyPi:
    .. code-block:: bash
        $ pip install django-localized-fields
2. Add ``localized_fields`` and ``django.contrib.postgres`` to your ``INSTALLED_APPS``:
     .. code-block:: bash
        INSTALLED_APPS = [
            ....
            'django.contrib.postgres',
            'localized_fields.apps.LocalizedFieldsConfig'
        ]
3. Set the database engine to ``psqlextra.backend``:
    .. code-block:: python
        DATABASES = {
            'default': {
                ...
                'ENGINE': 'psqlextra.backend'
            }
        }
3. Set ``LANGUAGES` and `LANGUAGE_CODE`` in your settings:
     .. code-block:: python
         LANGUAGE_CODE = 'en' # default language
         LANGUAGES = (
             ('en', 'English'),
             ('nl', 'Dutch'),
             ('ro', 'Romanian')
         )
Usage
-----
Preparation
^^^^^^^^^^^
Declare fields on your model as ``LocalizedField``:
.. code-block:: python
     from localized_fields.fields import LocalizedField
     class MyModel(models.Model):
         title = LocalizedField()
``django-localized-fields`` integrates with Django's i18n system, in order for certain languages to be available you have to correctly configure the ``LANGUAGES`` and ``LANGUAGE_CODE`` settings:
.. code-block:: python
     LANGUAGE_CODE = 'en' # default language
     LANGUAGES = (
          ('en', 'English'),
          ('nl', 'Dutch'),
          ('ro', 'Romanian')
     )
All the ``LocalizedField`` you define now will be available in the configured languages.
Basic usage
^^^^^^^^^^^
.. code-block:: python
     new = MyModel()
     new.title.en = 'english title'
     new.title.nl = 'dutch title'
     new.title.ro = 'romanian title'
     new.save()
By changing the active language you can control which language is presented:
.. code-block:: python
     from django.utils import translation
     translation.activate('nl')
     print(new.title) # prints 'dutch title'
     translation.activate('en')
     print(new.title) # prints 'english title'
Or get it in a specific language:
.. code-block:: python
     print(new.title.get('en')) # prints 'english title'
     print(new.title.get('ro')) # prints 'romanian title'
     print(new.title.get()) # whatever language is the primary one
You can also explicitly set a value in a certain language:
.. code-block:: python
     new.title.set('en', 'other english title')
     new.title.set('nl', 'other dutch title')
     new.title.ro = 'other romanian title'
Constraints
^^^^^^^^^^^
**Required/Optional**
At the moment, it is not possible to select two languages to be marked as required. The constraint is **not** enforced on a database level.
* Make the primary language **required** and the others optional (this is the **default**):
    .. code-block:: python
        class MyModel(models.Model):
            title = LocalizedField(required=True)
* Make all languages optional:
    .. code-block:: python
        class MyModel(models.Model):
            title = LocalizedField(null=True)
**Uniqueness**
By default the values stored in a ``LocalizedField`` are *not unique*. You can enforce uniqueness for certain languages. This uniqueness constraint is enforced on a database level using a ``UNIQUE INDEX``.
* Enforce uniqueness for one or more languages:
    .. code-block:: python
        class MyModel(models.Model):
            title = LocalizedField(uniqueness=['en', 'ro'])
* Enforce uniqueness for **all** languages:
    .. code-block:: python
        from localized_fields.util import get_language_codes
        class MyModel(models.Model):
            title = LocalizedField(uniqueness=get_language_codes())
* Enforce uniqueness for one ore more languages **together** (similar to Django's ``unique_together``):
    .. code-block:: python
        class MyModel(models.Model):
            title = LocalizedField(uniqueness=[('en', 'ro')])
* Enforce uniqueness for **all** languages **together**:
    .. code-block:: python
        from localized_fields.util import get_language_codes
        class MyModel(models.Model):
            title = LocalizedField(uniqueness=[(*get_language_codes())])
Other fields
^^^^^^^^^^^^
Besides ``LocalizedField``, there's also:
* ``LocalizedUniqueSlugField``
    Successor of ``LocalizedAutoSlugField`` that fixes concurrency issues and enforces
    uniqueness of slugs on a database level. Usage is the exact same:
          .. code-block:: python
              from localized_fields.models import LocalizedModel
              from localized_fields.fields import LocalizedField, LocalizedUniqueSlugField
              class MyModel(LocalizedModel):
                   title = LocalizedField()
                   slug = LocalizedUniqueSlugField(populate_from='title')
    By setting the option ``include_time=True``
          .. code-block:: python
               slug = LocalizedUniqueSlugField(populate_from='title', include_time=True)
    You can instruct the field to include a part of the current time into
    the resulting slug. This is useful if you're running into a lot of collisions.
* ``LocalizedAutoSlugField``
     Automatically creates a slug for every language from the specified field.
     Currently only supports ``populate_from``. Example usage:
          .. code-block:: python
              from localized_fields.fields import LocalizedField, LocalizedAutoSlugField
              class MyModel(LocalizedModel):
                   title = LocalizedField()
                   slug = LocalizedAutoSlugField(populate_from='title')
     This implementation is **NOT** concurrency safe, prefer ``LocalizedUniqueSlugField``.
* ``LocalizedBleachField``
     Automatically bleaches the content of the field.
          * django-bleach
     Example usage:
           .. code-block:: python
              from localized_fields.fields import LocalizedField, LocalizedBleachField
              class MyModel(models.Model):
                   title = LocalizedField()
                   description = LocalizedBleachField()
Experimental feature
^^^^^^^^^^^^^^^^^^^^
Enables the following experimental features:
    * ``LocalizedField`` will return ``None`` instead of an empty ``LocalizedValue`` if there is no database value.
.. code-block:: python
     LOCALIZED_FIELDS_EXPERIMENTAL = True
Django Admin Integration
^^^^^^^^^^^^^^^^^^^^^^^^
To enable widgets in the admin, you need to inherit from ``LocalizedFieldsAdminMixin``:
.. code-block:: python
    from django.contrib import admin
    from myapp.models import MyLocalizedModel
    from localized_fields.admin import LocalizedFieldsAdminMixin
    class MyLocalizedModelAdmin(LocalizedFieldsAdminMixin, admin.ModelAdmin):
        """Any admin options you need go here"""
    admin.site.register(MyLocalizedModel, MyLocalizedModelAdmin)
Frequently asked questions (FAQ)
--------------------------------
1. Does this package work with Python 2?
    No. Only Python 3.5 or newer is supported. We're using type hints. These do not work well under older versions of Python.
2. Does this package work with Django 1.X?
    No. Only Django 1.10 or newer is supported. This is because we rely on Django's ``HStoreField``.
3. Does this package come with support for Django Admin?
    Yes. Our custom fields come with a special form that will automatically be used in Django Admin if the field is of ``LocalizedField``.
4. Why should I pick this over any of the other translation packages out there?
    You should pick whatever you feel comfortable with. This package stores translations in your database without having to have translation tables. It however only works on PostgreSQL.
5. I am using PostgreSQL <9.6, can I use this?
    No. The ``hstore`` data type was introduced in PostgreSQL 9.6.
6. I am using this package. Can I give you some beer?
    Yes! If you're ever in the area of Cluj-Napoca, Romania, swing by :)
			
		Description
				
					Languages
				
				
								
								
									Python
								
								97.6%
							
						
							
								
								
									JavaScript
								
								0.9%
							
						
							
								
								
									CSS
								
								0.8%
							
						
							
								
								
									HTML
								
								0.7%