Changed handling of supported fields. By default CharField, TextField and subclasses of these fields are supported. Supported fields can be extended through the setting MODELTRANSLATION_CUSTOM_FIELDS. Support for related fields is experimental and these fields explicitly raise a FutureWarning now.

This commit is contained in:
Dirk Eschler 2010-08-27 08:39:41 +00:00
parent 6438ef28e5
commit 63fd7c0c7c
5 changed files with 54 additions and 34 deletions

View file

@ -11,6 +11,7 @@
ManyToManyField and OneToOneField.
(resolves issue 15)
CHANGED: Custom fields are extended instead of overridden.
CHANGED: Factored out settings into a separate settings.py and consistently
used an app specific settings prefix.
CHANGED: Refactored creation of translation fields and added handling of

View file

@ -303,6 +303,24 @@ the ``django.utils.i18n.get_language`` function to determine the current
language.
Supported fields
----------------
``Modeltranslation`` officially supports CharField and TextField.
*New in development version*
In most cases subclasses of these fields will work fine, too. Other fields
aren't supported and will throw an ``ImproperlyConfigured`` exception.
The list of supported fields can be extended. Just define a tuple of field names in your settings.py like this::
MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)
*Note:* This just prevents ``modeltranslation`` from throwing an
``ImproperlyConfigured`` exception. Any non text-like field will most likely
fail in one way or another. The feature is considered experimental and might be
replaced by a more sophisticated mechanism in future versions.
Set a default value
-------------------
*New in development version*
@ -334,8 +352,8 @@ following:
1. Removes the original field from every admin form by setting it
``editable=False``.
2. Copies the widget of the original field to each of it's translation fields.
3. Checks if the - now removed - original field was required and if so makes the
default translation field required instead.
3. Checks if the - now removed - original field was required and if so makes
the default translation field required instead.
TranslationAdmin in combination with other admin classes

View file

@ -4,7 +4,7 @@ from warnings import warn
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models.fields import Field, CharField
from django.db.models.fields import Field, CharField, TextField
from django.db.models.fields.related import (ForeignKey, OneToOneField,
ManyToManyField)
@ -16,20 +16,28 @@ from modeltranslation.utils import (get_language,
def create_translation_field(model, field_name, lang):
"""
Translation field factory.
Translation field factory. Returns a ``TranslationField`` based on a
fieldname and a language.
Tries to create an object in the form ``'Translation%s' % cls_name``
(e.g. ``TranslationForeignKey``, ``TranslationManyToManyField``) based on
``model`` and ``field_name``. The class is usually a subclass of
``TranslationField`` and is supposed to be implemented in this module. If
the class is listed in ``STD_TRANSLATION_FIELDS`` then ``TranslationField``
will be used to instantiate the object. If the class is neither implemented
nor in ``STD_TRANSLATION_FIELDS`` ``ImproperlyConfigured`` will be raised.
``TranslationField`` and is supposed to be implemented in this module.
The list of supported fields can be extended. Just define a tuple of field
names in your settings.py like this::
MODELTRANSLATION_CUSTOM_FIELDS = ('MyField', 'MyOtherField',)
If the class is a subclass of CharField or TextField then the standard
``TranslationField`` will be used to instantiate the object. If the class
is neither a subclass of CharField or TextField, nor implemented here, nor
in ``CUSTOM_FIELDS`` an ``ImproperlyConfigured`` exception will be raised.
"""
field = model._meta.get_field(field_name)
cls_name = field.__class__.__name__
# No subclass required for text fields
if cls_name in STD_TRANSLATION_FIELDS:
# No subclass required for text-like fields
if isinstance(field, (CharField, TextField)) or cls_name in CUSTOM_FIELDS:
return TranslationField(translated_field=field, language=lang)
# Try to instantiate translation field subclass
try:
@ -41,11 +49,11 @@ def create_translation_field(model, field_name, lang):
# Handle related fields
if cls_name in ('ForeignKey', 'OneToOneField', 'ManyToManyField'):
warn('Support for related fields is experimental and known to has '
'flaws. Only use it if you know what you are doing.', UserWarning)
to = field.rel.to._meta.object_name
return translation_field(translated_field=field, language=lang, to=to)
# TODO: Should never be reached?
return TranslationField(field, lang)
'flaws. Only use it if you know what you are doing.',
FutureWarning)
return translation_field(translated_field=field, language=lang,
to=field.rel.to._meta.object_name)
return TranslationField(translated_field=field, language=lang)
class TranslationField(Field):

View file

@ -26,20 +26,13 @@ if DEFAULT_LANGUAGE and DEFAULT_LANGUAGE not in AVAILABLE_LANGUAGES:
elif not DEFAULT_LANGUAGE:
DEFAULT_LANGUAGE = AVAILABLE_LANGUAGES[0]
# Only override this setting if you know what you are doing! It merely exist
# to test currently unsupported fields.
# FIXME: We can't seem to override this particular setting in tests.py
STD_TRANSLATION_FIELDS =\
getattr(settings, 'MODELTRANSLATION_STD_TRANSLATION_FIELDS',
('CharField', 'TextField', 'URLField', 'EmailField', 'XMLField',))
#try:
#if sys.argv[1] == 'test':
#STD_TRANSLATION_FIELDS =\
#getattr(settings, 'MODELTRANSLATION_STD_TRANSLATION_FIELDS',
#('CharField', 'TextField', 'URLField', 'EmailField',
#'XMLField', 'BooleanField', 'NullBooleanField',
#'IntegerField', 'BigIntegerField', 'PositiveIntegerField',
#'PositiveSmallIntegerField', 'SmallIntegerField',
#'CommaSeparatedIntegerField'))
#except IndexError:
#pass
CUSTOM_FIELDS =\
getattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS', ())
try:
if sys.argv[1] == 'test':
CUSTOM_FIELDS =\
getattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS',
('BooleanField',))
except IndexError:
pass

View file

@ -55,6 +55,9 @@ def add_localized_fields(model):
for field_name in translation_opts.fields:
localized_fields[field_name] = list()
for l in settings.LANGUAGES:
# Create a dynamic translation field
translation_field = create_translation_field(model=model,\
field_name=field_name, lang=l[0])
# Construct the name for the localized field
localized_field_name = build_localized_fieldname(field_name, l[0])
# Check if the model already has a field by that name
@ -63,9 +66,6 @@ def add_localized_fields(model):
"already contains a field named '%s'." %\
(instance.__class__.__name__,
localized_field_name))
# Create a dynamic translation field
translation_field = create_translation_field(model=model,\
field_name=field_name, lang=l[0])
# This approach implements the translation fields as full valid
# django model fields and therefore adds them via add_to_class
localized_field = model.add_to_class(localized_field_name,