diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a1d7299..1bcc811 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -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 diff --git a/docs/modeltranslation/modeltranslation.txt b/docs/modeltranslation/modeltranslation.txt index 48dc990..37848ef 100644 --- a/docs/modeltranslation/modeltranslation.txt +++ b/docs/modeltranslation/modeltranslation.txt @@ -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 diff --git a/modeltranslation/fields.py b/modeltranslation/fields.py index da1a45c..623cff4 100644 --- a/modeltranslation/fields.py +++ b/modeltranslation/fields.py @@ -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): diff --git a/modeltranslation/settings.py b/modeltranslation/settings.py index be12c5a..4a66b63 100644 --- a/modeltranslation/settings.py +++ b/modeltranslation/settings.py @@ -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 diff --git a/modeltranslation/translator.py b/modeltranslation/translator.py index b159c0b..9bf7d73 100644 --- a/modeltranslation/translator.py +++ b/modeltranslation/translator.py @@ -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,