mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-04-25 11:42:54 +03:00
Merge branch 'master' into widget_refactor
This commit is contained in:
commit
1accee0b59
@ -13,17 +13,20 @@ filter:
|
|||||||
build:
|
build:
|
||||||
environment:
|
environment:
|
||||||
python: '3.5.0'
|
python: '3.5.0'
|
||||||
node: 'v6.2.0'
|
|
||||||
variables:
|
variables:
|
||||||
DJANGO_SETTINGS_MODULES: settings
|
DJANGO_SETTINGS_MODULES: settings
|
||||||
DATABASE_URL: postgres://scrutinizer:scrutinizer@localhost:5434/localized_fields
|
DATABASE_URL: postgres://scrutinizer:scrutinizer@localhost:5434/localized_fields
|
||||||
postgresql: true
|
postgresql: true
|
||||||
redis: true
|
|
||||||
dependencies:
|
dependencies:
|
||||||
override:
|
override:
|
||||||
- 'pip install -r requirements/test.txt'
|
- 'pip install -r requirements/test.txt'
|
||||||
tests:
|
tests:
|
||||||
override:
|
override:
|
||||||
|
-
|
||||||
|
command: pep8 ./localized_fields/
|
||||||
|
-
|
||||||
|
command: flake8 ./localized_fields/
|
||||||
-
|
-
|
||||||
command: coverage run manage.py test
|
command: coverage run manage.py test
|
||||||
coverage:
|
coverage:
|
||||||
|
37
README.rst
37
README.rst
@ -12,9 +12,9 @@ django-localized-fields
|
|||||||
.. image:: https://badge.fury.io/py/django-localized-fields.svg
|
.. image:: https://badge.fury.io/py/django-localized-fields.svg
|
||||||
:target: https://pypi.python.org/pypi/django-localized-fields
|
: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.
|
``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.5 or newer, Django 1.10 or newer and PostgreSQL 9.6 or newer.
|
This package requires Python 3.5 or newer, Django 1.11 or newer and PostgreSQL 9.6 or newer.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
@ -129,21 +129,42 @@ Constraints
|
|||||||
|
|
||||||
**Required/Optional**
|
**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.
|
Constraints is enforced on a database level.
|
||||||
|
|
||||||
* Make the primary language **required** and the others optional (this is the **default**):
|
* Optional filling
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
title = LocalizedField(required=True)
|
title = LocalizedField(blank=True, null=True, required=False)
|
||||||
|
|
||||||
* Make all languages optional:
|
* Make translation required for any language
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class MyModel(models.Model):
|
class MyModel(models.Model):
|
||||||
title = LocalizedField(null=True)
|
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**
|
**Uniqueness**
|
||||||
|
|
||||||
@ -335,7 +356,7 @@ Frequently asked questions (FAQ)
|
|||||||
|
|
||||||
2. Does this package work with Django 1.X?
|
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``.
|
No. Only Django 1.11 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?
|
3. Does this package come with support for Django Admin?
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from typing import Union
|
from typing import Union, List
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
@ -27,10 +27,17 @@ class LocalizedField(HStoreField):
|
|||||||
# The descriptor to use for accessing the attribute off of the class.
|
# The descriptor to use for accessing the attribute off of the class.
|
||||||
descriptor_class = LocalizedValueDescriptor
|
descriptor_class = LocalizedValueDescriptor
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, required: Union[bool, List[str]]=None, **kwargs):
|
||||||
"""Initializes a new instance of :see:LocalizedField."""
|
"""Initializes a new instance of :see:LocalizedField."""
|
||||||
|
|
||||||
super(LocalizedField, self).__init__(*args, **kwargs)
|
super(LocalizedField, self).__init__(*args, required=required, **kwargs)
|
||||||
|
|
||||||
|
if (self.required is None and self.blank) or self.required is False:
|
||||||
|
self.required = []
|
||||||
|
elif self.required is None and not self.blank:
|
||||||
|
self.required = [settings.LANGUAGE_CODE]
|
||||||
|
elif self.required is True:
|
||||||
|
self.required = [lang_code for lang_code, _ in settings.LANGUAGES]
|
||||||
|
|
||||||
def contribute_to_class(self, model, name, **kwargs):
|
def contribute_to_class(self, model, name, **kwargs):
|
||||||
"""Adds this field to the specifed model.
|
"""Adds this field to the specifed model.
|
||||||
@ -170,9 +177,6 @@ class LocalizedField(HStoreField):
|
|||||||
# are any of the language fiels None/empty?
|
# are any of the language fiels None/empty?
|
||||||
is_all_null = True
|
is_all_null = True
|
||||||
for lang_code, _ in settings.LANGUAGES:
|
for lang_code, _ in settings.LANGUAGES:
|
||||||
# NOTE(seroy): use check for None, instead of
|
|
||||||
# `bool(value.get(lang_code))==True` condition, cause in this way
|
|
||||||
# we can not save '' value
|
|
||||||
if value.get(lang_code) is not None:
|
if value.get(lang_code) is not None:
|
||||||
is_all_null = False
|
is_all_null = False
|
||||||
break
|
break
|
||||||
@ -185,8 +189,8 @@ class LocalizedField(HStoreField):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def validate(self, value: LocalizedValue, *_):
|
def validate(self, value: LocalizedValue, *_):
|
||||||
"""Validates that the value for the primary language
|
"""Validates that the values has been filled in for all required
|
||||||
has been filled in.
|
languages
|
||||||
|
|
||||||
Exceptions are raises in order to notify the user
|
Exceptions are raises in order to notify the user
|
||||||
of invalid values.
|
of invalid values.
|
||||||
@ -199,36 +203,19 @@ class LocalizedField(HStoreField):
|
|||||||
if self.null:
|
if self.null:
|
||||||
return
|
return
|
||||||
|
|
||||||
primary_lang_val = getattr(value, settings.LANGUAGE_CODE)
|
for lang in self.required:
|
||||||
|
lang_val = getattr(value, settings.LANGUAGE_CODE)
|
||||||
|
|
||||||
# NOTE(seroy): use check for None, instead of `not primary_lang_val`
|
if lang_val is None:
|
||||||
# condition, cause in this way we can not save '' value
|
raise IntegrityError('null value in column "%s.%s" violates '
|
||||||
if primary_lang_val is None:
|
'not-null constraint' % (self.name, lang))
|
||||||
raise IntegrityError(
|
|
||||||
'null value in column "%s.%s" violates not-null constraint' % (
|
|
||||||
self.name,
|
|
||||||
settings.LANGUAGE_CODE
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
"""Gets the form field associated with this field."""
|
"""Gets the form field associated with this field."""
|
||||||
|
|
||||||
defaults = {
|
defaults = dict(
|
||||||
'form_class': LocalizedFieldForm
|
form_class=LocalizedFieldForm,
|
||||||
}
|
required=False if self.blank else self.required
|
||||||
|
)
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super().formfield(**defaults)
|
return super().formfield(**defaults)
|
||||||
|
|
||||||
def deconstruct(self):
|
|
||||||
"""Gets the values to pass to :see:__init__ when
|
|
||||||
re-creating this object."""
|
|
||||||
|
|
||||||
name, path, args, kwargs = super(
|
|
||||||
LocalizedField, self).deconstruct()
|
|
||||||
|
|
||||||
if self.uniqueness:
|
|
||||||
kwargs['uniqueness'] = self.uniqueness
|
|
||||||
|
|
||||||
return name, path, args, kwargs
|
|
||||||
|
@ -146,8 +146,6 @@ class LocalizedFileField(LocalizedField):
|
|||||||
|
|
||||||
def formfield(self, **kwargs):
|
def formfield(self, **kwargs):
|
||||||
defaults = {'form_class': LocalizedFileFieldForm}
|
defaults = {'form_class': LocalizedFileFieldForm}
|
||||||
if 'initial' in kwargs:
|
|
||||||
defaults['required'] = False
|
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super().formfield(**defaults)
|
return super().formfield(**defaults)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List
|
from typing import List, Union
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -19,28 +19,29 @@ class LocalizedFieldForm(forms.MultiValueField):
|
|||||||
field_class = forms.fields.CharField
|
field_class = forms.fields.CharField
|
||||||
value_class = LocalizedValue
|
value_class = LocalizedValue
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, required: Union[bool, List[str]]=False, **kwargs):
|
||||||
"""Initializes a new instance of :see:LocalizedFieldForm."""
|
"""Initializes a new instance of :see:LocalizedFieldForm."""
|
||||||
|
|
||||||
fields = []
|
fields = []
|
||||||
|
|
||||||
for lang_code, _ in settings.LANGUAGES:
|
for lang_code, _ in settings.LANGUAGES:
|
||||||
field_options = {'required': False}
|
field_options = dict(
|
||||||
|
required=required if type(required) is bool else (lang_code in
|
||||||
if lang_code == settings.LANGUAGE_CODE:
|
required),
|
||||||
field_options['required'] = kwargs.get('required', True)
|
label=lang_code
|
||||||
|
)
|
||||||
field_options['label'] = lang_code
|
|
||||||
fields.append(self.field_class(**field_options))
|
fields.append(self.field_class(**field_options))
|
||||||
|
|
||||||
super(LocalizedFieldForm, self).__init__(
|
super(LocalizedFieldForm, self).__init__(
|
||||||
fields,
|
fields,
|
||||||
|
required=required if type(required) is bool else True,
|
||||||
require_all_fields=False,
|
require_all_fields=False,
|
||||||
*args, **kwargs
|
*args, **kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
# set 'required' attribute for each widget separately
|
# set 'required' attribute for each widget separately
|
||||||
for f, w in zip(self.fields, self.widget.widgets):
|
for field, widget in zip(self.fields, self.widget.widgets):
|
||||||
w.is_required = f.required
|
widget.is_required = field.required
|
||||||
|
|
||||||
def compress(self, value: List[str]) -> value_class:
|
def compress(self, value: List[str]) -> value_class:
|
||||||
"""Compresses the values from individual fields
|
"""Compresses the values from individual fields
|
||||||
|
3
setup.py
3
setup.py
@ -18,7 +18,8 @@ setup(
|
|||||||
author_email='open-source@sectorlabs.ro',
|
author_email='open-source@sectorlabs.ro',
|
||||||
keywords=['django', 'localized', 'language', 'models', 'fields'],
|
keywords=['django', 'localized', 'language', 'models', 'fields'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'django-postgres-extra>=1.11'
|
'django-postgres-extra>=1.11',
|
||||||
|
'Django>=1.11'
|
||||||
],
|
],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Environment :: Web Environment',
|
'Environment :: Web Environment',
|
||||||
|
@ -9,11 +9,31 @@ from localized_fields.forms import LocalizedFieldForm
|
|||||||
from localized_fields.value import LocalizedValue
|
from localized_fields.value import LocalizedValue
|
||||||
|
|
||||||
from .data import get_init_values
|
from .data import get_init_values
|
||||||
|
from .fake_model import get_fake_model
|
||||||
|
|
||||||
|
|
||||||
class LocalizedFieldTestCase(TestCase):
|
class LocalizedFieldTestCase(TestCase):
|
||||||
"""Tests the :see:LocalizedField class."""
|
"""Tests the :see:LocalizedField class."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def test_init():
|
||||||
|
"""Tests whether the :see:__init__ function
|
||||||
|
correctly handles parameters"""
|
||||||
|
|
||||||
|
field = LocalizedField(blank=True)
|
||||||
|
assert field.required == []
|
||||||
|
|
||||||
|
field = LocalizedField(blank=False)
|
||||||
|
assert field.required == [settings.LANGUAGE_CODE]
|
||||||
|
|
||||||
|
field = LocalizedField(required=True)
|
||||||
|
assert field.required == [lang_code for lang_code, _ in
|
||||||
|
settings.LANGUAGES]
|
||||||
|
|
||||||
|
field = LocalizedField(required=False)
|
||||||
|
assert field.required == []
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_from_db_value():
|
def test_from_db_value():
|
||||||
"""Tests whether the :see:from_db_value function
|
"""Tests whether the :see:from_db_value function
|
||||||
@ -156,3 +176,90 @@ class LocalizedFieldTestCase(TestCase):
|
|||||||
LocalizedField().formfield(),
|
LocalizedField().formfield(),
|
||||||
LocalizedFieldForm
|
LocalizedFieldForm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# case optional filling
|
||||||
|
field = LocalizedField(blank=True, required=[])
|
||||||
|
assert not field.formfield().required
|
||||||
|
for field in field.formfield().fields:
|
||||||
|
assert not field.required
|
||||||
|
|
||||||
|
# case required for any language
|
||||||
|
field = LocalizedField(blank=False, required=[])
|
||||||
|
assert field.formfield().required
|
||||||
|
for field in field.formfield().fields:
|
||||||
|
assert not field.required
|
||||||
|
|
||||||
|
# case required for specific languages
|
||||||
|
required_langs = ['ro', 'nl']
|
||||||
|
field = LocalizedField(blank=False, required=required_langs)
|
||||||
|
assert field.formfield().required
|
||||||
|
for field in field.formfield().fields:
|
||||||
|
if field.label in required_langs:
|
||||||
|
assert field.required
|
||||||
|
else:
|
||||||
|
assert not field.required
|
||||||
|
|
||||||
|
# case required for all languages
|
||||||
|
field = LocalizedField(blank=False, required=True)
|
||||||
|
assert field.formfield().required
|
||||||
|
for field in field.formfield().fields:
|
||||||
|
assert field.required
|
||||||
|
|
||||||
|
def test_required_all(self):
|
||||||
|
"""Tests whether passing required=True properly validates
|
||||||
|
that all languages are filled in."""
|
||||||
|
|
||||||
|
model = get_fake_model(dict(
|
||||||
|
title=LocalizedField(required=True)
|
||||||
|
))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(ro='romanian', nl='dutch'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(nl='dutch'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(random='random'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict())
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=None)
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title='')
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=' ')
|
||||||
|
|
||||||
|
def test_required_some(self):
|
||||||
|
"""Tests whether passing an array to required,
|
||||||
|
properly validates whether the specified languages
|
||||||
|
are marked as required."""
|
||||||
|
|
||||||
|
model = get_fake_model(dict(
|
||||||
|
title=LocalizedField(required=['nl', 'ro'])
|
||||||
|
))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(ro='romanian', nl='dutch'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(nl='dutch'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict(random='random'))
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=dict())
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=None)
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title='')
|
||||||
|
|
||||||
|
with self.assertRaises(IntegrityError):
|
||||||
|
model.objects.create(title=' ')
|
||||||
|
@ -87,7 +87,7 @@ class LocalizedFileFieldTestCase(TestCase):
|
|||||||
instance = cls.FileFieldModel()
|
instance = cls.FileFieldModel()
|
||||||
instance.file = {'en': ContentFile("test", "testfilename")}
|
instance.file = {'en': ContentFile("test", "testfilename")}
|
||||||
instance._meta.get_field('file').pre_save(instance, False)
|
instance._meta.get_field('file').pre_save(instance, False)
|
||||||
assert instance.file.en._committed == True
|
assert instance.file.en._committed is True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def test_file_methods(cls):
|
def test_file_methods(cls):
|
||||||
@ -139,7 +139,7 @@ class LocalizedFileFieldTestCase(TestCase):
|
|||||||
value."""
|
value."""
|
||||||
|
|
||||||
value = LocalizedValue({'en': None})
|
value = LocalizedValue({'en': None})
|
||||||
assert LocalizedFileField().get_prep_value(None) == None
|
assert LocalizedFileField().get_prep_value(None) is None
|
||||||
assert isinstance(LocalizedFileField().get_prep_value(value), dict)
|
assert isinstance(LocalizedFileField().get_prep_value(value), dict)
|
||||||
assert LocalizedFileField().get_prep_value(value)['en'] == ''
|
assert LocalizedFileField().get_prep_value(value)['en'] == ''
|
||||||
|
|
||||||
@ -161,6 +161,5 @@ class LocalizedFileFieldTestCase(TestCase):
|
|||||||
name, path, args, kwargs = LocalizedFileField().deconstruct()
|
name, path, args, kwargs = LocalizedFileField().deconstruct()
|
||||||
assert 'upload_to' in kwargs
|
assert 'upload_to' in kwargs
|
||||||
assert 'storage' not in kwargs
|
assert 'storage' not in kwargs
|
||||||
name, path, \
|
name, path, args, kwargs = LocalizedFileField(storage='test').deconstruct()
|
||||||
args, kwargs = LocalizedFileField(storage='test').deconstruct()
|
|
||||||
assert 'storage' in kwargs
|
assert 'storage' in kwargs
|
||||||
|
@ -38,4 +38,3 @@ class LocalizedFileFieldFormTestCase(TestCase):
|
|||||||
value = [None] * len(settings.LANGUAGES)
|
value = [None] * len(settings.LANGUAGES)
|
||||||
expected_value = [''] * len(settings.LANGUAGES)
|
expected_value = [''] * len(settings.LANGUAGES)
|
||||||
assert formfield.bound_data(value, initial) == expected_value
|
assert formfield.bound_data(value, initial) == expected_value
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ class LocalizedFieldFormTestCase(TestCase):
|
|||||||
def test_init():
|
def test_init():
|
||||||
"""Tests whether the constructor correctly
|
"""Tests whether the constructor correctly
|
||||||
creates a field for every language."""
|
creates a field for every language."""
|
||||||
|
# case required for specific language
|
||||||
form = LocalizedFieldForm()
|
form = LocalizedFieldForm(required=[settings.LANGUAGE_CODE])
|
||||||
|
|
||||||
for (lang_code, _), field in zip(settings.LANGUAGES, form.fields):
|
for (lang_code, _), field in zip(settings.LANGUAGES, form.fields):
|
||||||
assert field.label == lang_code
|
assert field.label == lang_code
|
||||||
@ -22,6 +22,25 @@ class LocalizedFieldFormTestCase(TestCase):
|
|||||||
else:
|
else:
|
||||||
assert not field.required
|
assert not field.required
|
||||||
|
|
||||||
|
# case required for all languages
|
||||||
|
form = LocalizedFieldForm(required=True)
|
||||||
|
assert form.required
|
||||||
|
for field in form.fields:
|
||||||
|
assert field.required
|
||||||
|
|
||||||
|
# case optional filling
|
||||||
|
form = LocalizedFieldForm(required=False)
|
||||||
|
assert not form.required
|
||||||
|
for field in form.fields:
|
||||||
|
assert not field.required
|
||||||
|
|
||||||
|
# case required for any language
|
||||||
|
form = LocalizedFieldForm(required=[])
|
||||||
|
assert form.required
|
||||||
|
for field in form.fields:
|
||||||
|
assert not field.required
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_compress():
|
def test_compress():
|
||||||
"""Tests whether the :see:compress function
|
"""Tests whether the :see:compress function
|
||||||
|
@ -124,7 +124,7 @@ class LocalizedSlugFieldTestCase(TestCase):
|
|||||||
def generate_slug(instance):
|
def generate_slug(instance):
|
||||||
return instance.title
|
return instance.title
|
||||||
|
|
||||||
model = get_fake_model({
|
get_fake_model({
|
||||||
'title': LocalizedField(),
|
'title': LocalizedField(),
|
||||||
'slug': LocalizedUniqueSlugField(populate_from=generate_slug)
|
'slug': LocalizedUniqueSlugField(populate_from=generate_slug)
|
||||||
})
|
})
|
||||||
@ -138,7 +138,6 @@ class LocalizedSlugFieldTestCase(TestCase):
|
|||||||
for lang_code, lang_name in settings.LANGUAGES:
|
for lang_code, lang_name in settings.LANGUAGES:
|
||||||
assert obj.slug.get(lang_code) == 'title-%s' % lang_name.lower()
|
assert obj.slug.get(lang_code) == 'title-%s' % lang_name.lower()
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def test_populate_multiple_from_fields():
|
def test_populate_multiple_from_fields():
|
||||||
"""Tests whether populating the slug from multiple
|
"""Tests whether populating the slug from multiple
|
||||||
|
@ -149,8 +149,6 @@ class LocalizedValueTestCase(TestCase):
|
|||||||
__str__'s fallback functionality properly respects
|
__str__'s fallback functionality properly respects
|
||||||
the LOCALIZED_FIELDS_FALLBACKS setting."""
|
the LOCALIZED_FIELDS_FALLBACKS setting."""
|
||||||
|
|
||||||
test_value = 'myvalue'
|
|
||||||
|
|
||||||
settings.LOCALIZED_FIELDS_FALLBACKS = {
|
settings.LOCALIZED_FIELDS_FALLBACKS = {
|
||||||
'nl': ['ro']
|
'nl': ['ro']
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
@ -55,3 +56,12 @@ class LocalizedFieldWidgetTestCase(TestCase):
|
|||||||
attrs=dict(required=True))
|
attrs=dict(required=True))
|
||||||
assert context['widget']['subwidgets'][0]['attrs']['required']
|
assert context['widget']['subwidgets'][0]['attrs']['required']
|
||||||
assert 'required' not in context['widget']['subwidgets'][1]['attrs']
|
assert 'required' not in context['widget']['subwidgets'][1]['attrs']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def test_render():
|
||||||
|
"""Tests whether the :see:LocalizedFieldWidget correctly
|
||||||
|
render."""
|
||||||
|
|
||||||
|
widget = LocalizedFieldWidget()
|
||||||
|
output = widget.render(name='title', value=None)
|
||||||
|
assert bool(re.search('<label (.|\n|\t)*>\w+<\/label>', output))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user