Replace README with Markdown version

This commit is contained in:
Swen Kooij 2019-10-20 17:43:41 +03:00
parent 3bf7926c57
commit e6ce2da161
3 changed files with 60 additions and 409 deletions

59
README.md Normal file
View File

@ -0,0 +1,59 @@
| | | |
|--------------------|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :white_check_mark: | **Tests** | [![CircleCI](https://circleci.com/gh/SectorLabs/django-localized-fields/tree/master.svg?style=svg)](https://circleci.com/gh/SectorLabs/django-localized-fields/tree/master) |
| :memo: | **License** | [![License](https://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) |
| :package: | **PyPi** | [![PyPi](https://badge.fury.io/py/django-localized-fields.svg)](https://pypi.python.org/pypi/django-localized-fields) |
| <img src="https://icon-library.net/images/django-icon/django-icon-0.jpg" width="22px" height="22px" align="center" /> | **Django Versions** | 2.0, 2.1, 2.2 |
| <img src="http://www.iconarchive.com/download/i73027/cornmanthe3rd/plex/Other-python.ico" width="22px" height="22px" align="center" /> | **Python Versions** | 3.7, 3.8 |
| :book: | **Documentation** | [Read The Docs](https://django-localized-fields.readthedocs.io) |
| :warning: | **Upgrade** | [Upgrade fom v5.x](https://django-localized-fields.readthedocs.io/releases)
| :checkered_flag: | **Installation** | [Installation Guide](https://django-localized-fields.readthedocs.io/#installation) |
`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` since Django 1.10.
---
:warning: **This README is for v6 which is currently under development. See the `v5.x` branch for v5.x.**
---
## Working with the code
### Prerequisites
* PostgreSQL 10 or newer.
* Django 2.0 or newer.
* Python 3.7 or newer.
### Getting started
1. Clone the repository:
λ git clone https://github.com/SectorLabs/django-localized-fields.git
2. Create a virtual environment:
λ cd django-localized-fields
λ virtualenv env
λ source env/bin/activate
3. Create a postgres user for use in tests (skip if your default user is a postgres superuser):
λ createuser --superuser psqlextra --pwprompt
λ export DATABASE_URL=postgres://psqlextra:<password>@localhost/psqlextra
Hint: if you're using virtualenvwrapper, you might find it beneficial to put
the ``export`` line in ``$VIRTUAL_ENV/bin/postactivate`` so that it's always
available when using this virtualenv.
4. Install the development/test dependencies:
λ pip install -r requirements/test.txt
λ pip install -r requirements/analysis.txt
5. Run the tests:
λ tox
7. Auto-format code, sort imports and auto-fix linting errors:
λ python setup.py fix

View File

@ -1,408 +0,0 @@
django-localized-fields
=======================
.. image:: https://circleci.com/gh/SectorLabs/django-localized-fields.svg?style=svg
:target: https://circleci.com/gh/SectorLabs/django-localized-fields
.. image:: https://img.shields.io/github/license/SectorLabs/django-localized-fields.svg
:target: https://github.com/SectorLabs/django-localized-fields/blob/master/LICENSE.md
.. 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`` since Django 1.10.
This package requires Python 3.7 or newer, Django 2.0 or newer and PostgreSQL 10 or newer.
Contributors
------------
* `seroy <https://github.com/seroy/>`_
* `umazalakain <https://github.com/umazalakain/>`_
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')
)
4. Apply migrations to enable the HStore extension:
.. code-block:: bash
python manage.py migrate
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
print(new.title.get('ar', 'haha')) # prints 'haha' if there is no value in arabic
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**
Constraints are enforced on a database level.
* Optional filling
.. code-block:: python
class MyModel(models.Model):
title = LocalizedField(blank=True, null=True, required=False)
* Make translation required for any language
.. code-block:: python
class MyModel(models.Model):
title = LocalizedField(blank=False, null=False, required=False)
* Make translation required for specific languages
.. code-block:: python
class MyModel(models.Model):
title = LocalizedField(blank=False, null=False, required=['en', 'ro'])
* Make translation required for all languages
.. code-block:: python
class MyModel(models.Model):
title = LocalizedField(blank=False, null=False, required=True)
* By default the primary language **required** and the others optional:
.. code-block:: python
class MyModel(models.Model):
title = LocalizedField()
**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')
``populate_from`` can be:
- The name of a field.
.. code-block:: python
slug = LocalizedUniqueSlugField(populate_from='name', include_time=True)
- A callable.
.. code-block:: python
def generate_slug(instance):
return instance.title
slug = LocalizedUniqueSlugField(populate_from=generate_slug, include_time=True)
- A tuple of names of fields.
.. code-block:: python
slug = LocalizedUniqueSlugField(populate_from=('name', 'beer') include_time=True)
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.
* ``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()
* ``LocalizedIntegerField``
This is an experimental field type introduced in version 5.0 and is subject to change. It also has
some pretty major downsides due to the fact that values are stored as strings and are converted
back and forth.
Allows storing integers in multiple languages. This works exactly like ``LocalizedField`` except that
all values must be integers. Do note that values are stored as strings in your database because
the backing field type is ``hstore``, which only allows storing strings. The ``LocalizedIntegerField``
takes care of ensuring that all values are integers and converts the stored strings back to integers
when retrieving them from the database. Do not expect to be able to do queries such as:
.. code-block:: python
MyModel.objects.filter(score__en__gt=1)
* ``LocalizedCharField`` and ``LocalizedTextField``
These fields following the Django convention for string-based fields use the empty string as value for “no data”, not NULL.
``LocalizedCharField`` uses ``TextInput`` (``<input type="text">``) widget for render.
Example usage:
.. code-block:: python
from localized_fields.fields import LocalizedCharField, LocalizedTextField
class MyModel(models.Model):
title = LocalizedCharField()
description = LocalizedTextField()
* ``LocalizedFileField``
A file-upload field
Parameter ``upload_to`` supports ``lang`` parameter for string formatting or as function argument (in case if ``upload_to`` is callable).
Example usage:
.. code-block:: python
from localized_fields.fields import LocalizedFileField
def my_directory_path(instance, filename, lang):
# file will be uploaded to MEDIA_ROOT/<lang>/<id>_<filename>
return '{0}/{0}_{1}'.format(lang, instance.id, filename)
class MyModel(models.Model):
file1 = LocalizedFileField(upload_to='uploads/{lang}/')
file2 = LocalizedFileField(upload_to=my_directory_path)
In template you can access to file attributes:
.. code-block:: django
{# For current active language: #}
{{ model.file.url }} {# output file url #}
{{ model.file.name }} {# output file name #}
{# Or get it in a specific language: #}
{{ model.file.ro.url }} {# output file url for romanian language #}
{{ model.file.ro.name }} {# output file name for romanian language #}
To get access to file instance for current active language use ``localized`` method:
.. code-block:: python
model.file.localized()
Experimental feature
^^^^^^^^^^^^^^^^^^^^
Enables the following experimental features:
* ``LocalizedField`` will return ``None`` instead of an empty ``LocalizedValue`` if there is no database value.
* ``LocalizedField`` lookups will lookup by currently active language instead of HStoreField
.. 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)
.. image:: ./images/admin-widget.png
:alt: The appearance of admin widget
Frequently asked questions (FAQ)
--------------------------------
1. Does this package work with Python 2?
No. Only Python 3.7 or newer is supported. We're using type hints. These do not work well under older versions of Python.
2. With what Django versions does this package work?
Only Django 2.x or newer is supported. This is because we rely on Django's ``HStoreField`` and template-based widget rendering.
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 <10, 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 :)

View File

@ -29,7 +29,7 @@ def create_command(text, commands):
with open(
os.path.join(os.path.dirname(__file__), "README.rst"), encoding="utf-8"
os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8"
) as readme:
README = readme.read()