From 3f4a6eb472e9fb30c3b8356364038f6ef2a296d7 Mon Sep 17 00:00:00 2001 From: Dirk Eschler Date: Mon, 19 Apr 2010 10:52:57 +0000 Subject: [PATCH] Validated codebase against pep8. --- modeltranslation/admin.py | 38 ++++-- modeltranslation/fields.py | 62 ++++----- .../commands/update_translation_fields.py | 30 +++-- modeltranslation/models.py | 8 +- modeltranslation/tests.py | 117 +++++++++-------- modeltranslation/translator.py | 119 ++++++++++-------- modeltranslation/utils.py | 74 +++++------ 7 files changed, 237 insertions(+), 211 deletions(-) diff --git a/modeltranslation/admin.py b/modeltranslation/admin.py index 58182b0..b51e3a3 100644 --- a/modeltranslation/admin.py +++ b/modeltranslation/admin.py @@ -28,11 +28,14 @@ class TranslationAdminBase(object): # For every localized field copy the widget from the original field if db_field.name in trans_opts.localized_fieldnames_rev: orig_fieldname = trans_opts.localized_fieldnames_rev[db_field.name] - orig_formfield = self.formfield_for_dbfield(self.model._meta.get_field(orig_fieldname), **kwargs) + orig_formfield = self.formfield_for_dbfield( \ + self.model._meta.get_field(orig_fieldname), + **kwargs) # In case the original form field was required, make the default # translation field required instead. - if db_field.language == settings.LANGUAGES[0][0] and orig_formfield.required: + if db_field.language == settings.LANGUAGES[0][0] and \ + orig_formfield.required: orig_formfield.required = False orig_formfield.blank = True field.required = True @@ -40,6 +43,7 @@ class TranslationAdminBase(object): field.widget = deepcopy(orig_formfield.widget) + class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) @@ -53,7 +57,7 @@ class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) - fields_new[index:index+1] = translation_fields + fields_new[index:index + 1] = translation_fields self.fields = fields_new if self.fieldsets: @@ -65,7 +69,7 @@ class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) - fields_new[index:index+1] = translation_fields + fields_new[index:index + 1] = translation_fields dct['fields'] = fields_new self.fieldsets = fieldsets_new @@ -77,8 +81,9 @@ class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) - editable_new[index:index+1] = translation_fields - display_new[display_index:display_index+1] = translation_fields + editable_new[index:index + 1] = translation_fields + display_new[display_index:display_index + 1] = \ + translation_fields self.list_editable = editable_new self.list_display = display_new @@ -91,7 +96,8 @@ class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): def formfield_for_dbfield(self, db_field, **kwargs): # Call the baseclass function to get the formfield - field = super(TranslationAdmin, self).formfield_for_dbfield(db_field, **kwargs) + field = super(TranslationAdmin, self).formfield_for_dbfield(db_field, + **kwargs) self.patch_translation_field(db_field, field, **kwargs) return field @@ -99,7 +105,8 @@ class TranslationAdmin(admin.ModelAdmin, TranslationAdminBase): class TranslationTabularInline(admin.TabularInline, TranslationAdminBase): def formfield_for_dbfield(self, db_field, **kwargs): # Call the baseclass function to get the formfield - field = super(TranslationTabularInline, self).formfield_for_dbfield(db_field, **kwargs) + field = super(TranslationTabularInline, + self).formfield_for_dbfield(db_field, **kwargs) self.patch_translation_field(db_field, field, **kwargs) return field @@ -107,22 +114,27 @@ class TranslationTabularInline(admin.TabularInline, TranslationAdminBase): class TranslationStackedInline(admin.StackedInline, TranslationAdminBase): def formfield_for_dbfield(self, db_field, **kwargs): # Call the baseclass function to get the formfield - field = super(TranslationStackedInline, self).formfield_for_dbfield(db_field, **kwargs) + field = super(TranslationStackedInline, + self).formfield_for_dbfield(db_field, **kwargs) self.patch_translation_field(db_field, field, **kwargs) return field -class TranslationGenericTabularInline(generic.GenericTabularInline, TranslationAdminBase): +class TranslationGenericTabularInline(generic.GenericTabularInline, + TranslationAdminBase): def formfield_for_dbfield(self, db_field, **kwargs): # Call the baseclass function to get the formfield - field = super(TranslationGenericTabularInline, self).formfield_for_dbfield(db_field, **kwargs) + field = super(TranslationGenericTabularInline, + self).formfield_for_dbfield(db_field, **kwargs) self.patch_translation_field(db_field, field, **kwargs) return field -class TranslationGenericStackedInline(generic.GenericStackedInline, TranslationAdminBase): +class TranslationGenericStackedInline(generic.GenericStackedInline, + TranslationAdminBase): def formfield_for_dbfield(self, db_field, **kwargs): # Call the baseclass function to get the formfield - field = super(TranslationGenericStackedInline, self).formfield_for_dbfield(db_field, **kwargs) + field = super(TranslationGenericStackedInline, + self).formfield_for_dbfield(db_field, **kwargs) self.patch_translation_field(db_field, field, **kwargs) return field diff --git a/modeltranslation/fields.py b/modeltranslation/fields.py index caa2537..5498d6b 100644 --- a/modeltranslation/fields.py +++ b/modeltranslation/fields.py @@ -4,11 +4,12 @@ from django.db.models.fields import Field, CharField from modeltranslation.utils import get_language, build_localized_fieldname + class TranslationField(Field): """ The translation field functions as a proxy to the original field which is - wrapped. - + wrapped. + For every field defined in the model's ``TranslationOptions`` localized versions of that field are added to the model depending on the languages given in ``settings.LANGUAGES``. @@ -16,55 +17,56 @@ class TranslationField(Field): If for example there is a model ``News`` with a field ``title`` which is registered for translation and the ``settings.LANGUAGES`` contains the ``de`` and ``en`` languages, the fields ``title_de`` and ``title_en`` will - be added to the model class. These fields are realized using this + be added to the model class. These fields are realized using this descriptor. - + The translation field needs to know which language it contains therefore that needs to be specified when the field is created. - """ def __init__(self, translated_field, language, *args, **kwargs): # Store the originally wrapped field for later self.translated_field = translated_field self.language = language - + # Update the dict of this field with the content of the original one # This might be a bit radical?! Seems to work though... - self.__dict__.update(translated_field.__dict__) - + self.__dict__.update(translated_field.__dict__) + # Translation are always optional (for now - maybe add some parameters # to the translation options for configuring this) self.null = True self.blank = True - + # Adjust the name of this field to reflect the language self.attname = build_localized_fieldname(translated_field.name, language) self.name = self.attname - + # Copy the verbose name and append a language suffix (will e.g. in the # admin). This might be a proxy function so we have to check that here. - if hasattr(translated_field.verbose_name, '_proxy____unicode_cast'): - verbose_name = translated_field.verbose_name._proxy____unicode_cast() + if hasattr(translated_field.verbose_name, '_proxy____unicode_cast'): + verbose_name = \ + translated_field.verbose_name._proxy____unicode_cast() else: - verbose_name = translated_field.verbose_name + verbose_name = translated_field.verbose_name self.verbose_name = '%s [%s]' % (verbose_name, language) - - def pre_save(self, model_instance, add): + + def pre_save(self, model_instance, add): val = super(TranslationField, self).pre_save(model_instance, add) - if get_language() == self.language and not add: + if get_language() == self.language and not add: # Rule is: 3. Assigning a value to a translation field of the # default language also updates the original field model_instance.__dict__[self.translated_field.name] = val return val - + def get_internal_type(self): return self.translated_field.get_internal_type() - - #def contribute_to_class(self, cls, name): + + #def contribute_to_class(self, cls, name): #super(TranslationField, self).contribute_to_class(cls, name) - ##setattr(cls, 'get_%s_display' % self.name, curry(cls._get_FIELD_display, field=self)) - + ##setattr(cls, 'get_%s_display' % self.name, + ##curry(cls._get_FIELD_display, field=self)) + def south_field_triple(self): """Returns a suitable description of this field for South.""" # We'll just introspect the _actual_ field. @@ -74,7 +76,7 @@ class TranslationField(Field): args, kwargs = introspector(self.translated_field) # That's our definition! return (field_class, args, kwargs) - + def formfield(self, *args, **kwargs): """Preserves the widget of the translated field.""" trans_formfield = self.translated_field.formfield(*args, **kwargs) @@ -85,24 +87,24 @@ class TranslationField(Field): #class CurrentLanguageField(CharField): #def __init__(self, **kwargs): - #super(CurrentLanguageField, self).__init__(null=True, max_length=5, **kwargs) - + #super(CurrentLanguageField, self).__init__(null=True, max_length=5, + #**kwargs) + #def contribute_to_class(self, cls, name): #super(CurrentLanguageField, self).contribute_to_class(cls, name) #registry = CurrentLanguageFieldRegistry() #registry.add_field(cls, self) - - + + #class CurrentLanguageFieldRegistry(object): #_registry = {} - + #def add_field(self, model, field): #reg = self.__class__._registry.setdefault(model, []) #reg.append(field) - + #def get_fields(self, model): #return self.__class__._registry.get(model, []) - + #def __contains__(self, model): #return model in self.__class__._registry - \ No newline at end of file diff --git a/modeltranslation/management/commands/update_translation_fields.py b/modeltranslation/management/commands/update_translation_fields.py index c0328e2..adb5e6d 100644 --- a/modeltranslation/management/commands/update_translation_fields.py +++ b/modeltranslation/management/commands/update_translation_fields.py @@ -1,24 +1,30 @@ # -*- coding: utf-8 -*- from django.conf import settings -from django.core.management.base import BaseCommand, CommandError, NoArgsCommand +from django.core.management.base import (BaseCommand, CommandError, + NoArgsCommand) from modeltranslation.translator import translator from modeltranslation.utils import build_localized_fieldname + class Command(NoArgsCommand): help = 'Updates the default translation fields of all or the specified' \ 'translated application using the value of the original field.' - - def handle(self, **options): - default_lang = settings.LANGUAGES[0][0] - print "Using default language:", default_lang - - for model, trans_opts in translator._registry.items(): - print "Updating data of model '%s'" % model - for obj in model.objects.all(): + + def handle(self, **options): + default_lang = settings.LANGUAGES[0][0] + print "Using default language:", default_lang + + for model, trans_opts in translator._registry.items(): + print "Updating data of model '%s'" % model + for obj in model.objects.all(): for fieldname in trans_opts.fields: - def_lang_fieldname = build_localized_fieldname(fieldname, default_lang) - # print "setting %s from %s to %s." % (def_lang_fieldname, fieldname, obj.__dict__[fieldname]) + def_lang_fieldname = \ + build_localized_fieldname(fieldname, default_lang) + #print "setting %s from %s to %s." % \ + #(def_lang_fieldname, fieldname, + #obj.__dict__[fieldname]) if not getattr(obj, def_lang_fieldname): - setattr(obj, def_lang_fieldname, obj.__dict__[fieldname]) + setattr(obj, def_lang_fieldname, + obj.__dict__[fieldname]) obj.save() diff --git a/modeltranslation/models.py b/modeltranslation/models.py index 8fa0981..739c897 100644 --- a/modeltranslation/models.py +++ b/modeltranslation/models.py @@ -8,13 +8,13 @@ from django.db import models from modeltranslation.translator import translator # Every model registered with the modeltranslation.translator.translator -# is patched to contain additional localized versions for every +# is patched to contain additional localized versions for every # field specified in the model's translation options. -# Import the project's global "translation.py" which registers model +# Import the project's global "translation.py" which registers model # classes and their translation options with the translator object. if getattr(settings, 'TRANSLATION_REGISTRY', False): - try: + try: __import__(settings.TRANSLATION_REGISTRY, {}, {}, ['']) except ImportError: sys.stderr.write("modeltranslation: Can't import module '%s'.\n" @@ -27,7 +27,7 @@ if getattr(settings, 'TRANSLATION_REGISTRY', False): import traceback traceback.print_exc() - # After importing all translation modules, all translation classes are + # After importing all translation modules, all translation classes are # registered with the translator. if settings.DEBUG: try: diff --git a/modeltranslation/tests.py b/modeltranslation/tests.py index a3aa454..3e0f39b 100644 --- a/modeltranslation/tests.py +++ b/modeltranslation/tests.py @@ -29,54 +29,52 @@ translator.translator._registry = {} translator.translator.register(TestModel, TestTranslationOptions) -class ModelTranslationTest(TestCase): +class ModelTranslationTest(TestCase): """Basic tests for the modeltranslation application.""" - urls = 'modeltranslation.testurls' - - def setUp(self): + + def setUp(self): trans_real.activate("de") - + def tearDown(self): trans_real.deactivate() - def test_registration(self): self.client.post('/set_language/', data={'language': 'de'}) - #self.client.session['django_language'] = 'de-de' + #self.client.session['django_language'] = 'de-de' #self.client.cookies[settings.LANGUAGE_COOKIE_NAME] = 'de-de' - + langs = tuple(l[0] for l in settings.LANGUAGES) self.failUnlessEqual(2, len(langs)) self.failUnless('de' in langs) - self.failUnless('en' in langs) + self.failUnless('en' in langs) self.failUnless(translator.translator) # Check that only one model is registered for translation self.failUnlessEqual(len(translator.translator._registry), 1) - + # Try to unregister a model that is not registered self.assertRaises(translator.NotRegistered, translator.translator.unregister, User) - + # Try to get options for a model that is not registered self.assertRaises(translator.NotRegistered, translator.translator.get_options_for_model, User) - - def test_translated_models(self): + + def test_translated_models(self): # First create an instance of the test model to play with inst = TestModel.objects.create(title="Testtitle", text="Testtext") field_names = dir(inst) self.failUnless('id' in field_names) self.failUnless('title' in field_names) self.failUnless('text' in field_names) - self.failUnless('title_de' in field_names) - self.failUnless('title_en' in field_names) - self.failUnless('text_de' in field_names) - self.failUnless('text_en' in field_names) - + self.failUnless('title_de' in field_names) + self.failUnless('title_en' in field_names) + self.failUnless('text_de' in field_names) + self.failUnless('text_en' in field_names) + inst.delete() - + def test_set_translation(self): self.failUnlessEqual(get_language(), "de") # First create an instance of the test model to play with @@ -88,55 +86,55 @@ class ModelTranslationTest(TestCase): inst2 = TestModel(title=title2_de, text="Testtext") inst1.save() inst2.save() - + self.failUnlessEqual(inst1.title, title1_de) self.failUnlessEqual(inst1.title_en, title1_en) - + self.failUnlessEqual(inst2.title, title2_de) - self.failUnlessEqual(inst2.title_en, None) - + self.failUnlessEqual(inst2.title_en, None) + del inst1 del inst2 - + # Check that the translation fields are correctly saved and provide the # correct value when retrieving them again. n = TestModel.objects.get(title=title1_de) self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.title_en, title1_en) - + def test_titleonly(self): title1_de = "title de" n = TestModel.objects.create(title=title1_de) self.failUnlessEqual(n.title, title1_de) - # Because the original field "title" was specified in the constructor - # it is directly passed into the instance's __dict__ and the descriptor + # Because the original field "title" was specified in the constructor + # it is directly passed into the instance's __dict__ and the descriptor # which updates the associated default translation field is not called # and the default translation will be None. self.failUnlessEqual(n.title_de, None) self.failUnlessEqual(n.title_en, None) - + # Now assign the title, that triggers the descriptor and the default # translation field is updated n.title = title1_de self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.title_de, title1_de) self.failUnlessEqual(n.title_en, None) - - def test_rule1(self): + + def test_rule1(self): """ - Rule 1: Reading the value from the original field returns the value in + Rule 1: Reading the value from the original field returns the value in translated to the current language. """ title1_de = "title de" title1_en = "title en" text_de = "Dies ist ein deutscher Satz" text_en = "This is an english sentence" - + # Test 1. n = TestModel.objects.create(title_de=title1_de, title_en=title1_en, text_de=text_de, text_en=text_en) n.save() - + # language is set to "de" at this point self.failUnlessEqual(get_language(), "de") self.failUnlessEqual(n.title, title1_de) @@ -150,9 +148,9 @@ class ModelTranslationTest(TestCase): self.failUnlessEqual(get_language(), "en") # Title should now be return the english one (just by switching the # language) - self.failUnlessEqual(n.title, title1_en) - self.failUnlessEqual(n.text, text_en) - + self.failUnlessEqual(n.title, title1_en) + self.failUnlessEqual(n.text, text_en) + n = TestModel.objects.create(title_de=title1_de, title_en=title1_en, text_de=text_de, text_en=text_en) n.save() @@ -168,8 +166,8 @@ class ModelTranslationTest(TestCase): self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.text, text_de) trans_real.deactivate() - - def test_rule2(self): + + def test_rule2(self): """ Rule 2: Assigning a value to the original field also updates the value in the associated translation field of the default language @@ -177,48 +175,48 @@ class ModelTranslationTest(TestCase): self.failUnlessEqual(get_language(), "de") title1_de = "title de" title1_en = "title en" - n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) + n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.title_de, title1_de) self.failUnlessEqual(n.title_en, title1_en) - - title2 = "Neuer Titel" + + title2 = "Neuer Titel" n.title = title2 n.save() self.failUnlessEqual(n.title, title2) self.failUnlessEqual(n.title, n.title_de) - + trans_real.activate("en") self.failUnlessEqual(get_language(), "en") title3 = "new title" - + n.title = title3 n.title_de = title1_de n.save() self.failUnlessEqual(n.title, title3) self.failUnlessEqual(n.title, n.title_en) self.failUnlessEqual(title1_de, n.title_de) - - trans_real.deactivate() - + + trans_real.deactivate() + def test_rule3(self): """ - Rule 3: Assigning a value to a translation field of the default language - also updates the original field - note that the value of the original - field will not be updated until the model instance is saved. + Rule 3: Assigning a value to a translation field of the default + language also updates the original field - note that the value of the + original field will not be updated until the model instance is saved. """ title1_de = "title de" title1_en = "title en" - n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) + n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) self.failUnlessEqual(get_language(), "de") self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.title_de, title1_de) self.failUnlessEqual(n.title_en, title1_en) - + n.title_de = "Neuer Titel" n.save() self.failUnlessEqual(n.title, n.title_de) - + # Now switch to "en" trans_real.activate("en") self.failUnlessEqual(get_language(), "en") @@ -227,21 +225,21 @@ class ModelTranslationTest(TestCase): n.save() self.failUnlessEqual(n.title, n.title_en) trans_real.deactivate() - - def test_rule4(self): + + def test_rule4(self): """ - Rule 4: If both fields - the original and the translation field of the - default language - are updated at the same time, the translation field + Rule 4: If both fields - the original and the translation field of the + default language - are updated at the same time, the translation field wins. """ self.failUnlessEqual(get_language(), "de") title1_de = "title de" title1_en = "title en" - n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) + n = TestModel.objects.create(title_de=title1_de, title_en=title1_en) self.failUnlessEqual(n.title, title1_de) self.failUnlessEqual(n.title_de, title1_de) self.failUnlessEqual(n.title_en, title1_en) - + title2_de = "neu de" title2_en = "new en" title_foo = "foo" @@ -252,10 +250,9 @@ class ModelTranslationTest(TestCase): self.failUnlessEqual(n.title, title2_de) self.failUnlessEqual(n.title_de, title2_de) self.failUnlessEqual(n.title_en, title2_en) - + n.title = title_foo n.save() self.failUnlessEqual(n.title, title_foo) self.failUnlessEqual(n.title_de, title_foo) self.failUnlessEqual(n.title_en, title2_en) - diff --git a/modeltranslation/translator.py b/modeltranslation/translator.py index d934cdf..0a55362 100644 --- a/modeltranslation/translator.py +++ b/modeltranslation/translator.py @@ -6,12 +6,14 @@ from django.db.models import signals from django.db.models.base import ModelBase from django.utils.functional import curry -from modeltranslation.fields import TranslationField -from modeltranslation.utils import TranslationFieldDescriptor, build_localized_fieldname +from modeltranslation.fields import TranslationField +from modeltranslation.utils import (TranslationFieldDescriptor, + build_localized_fieldname) + class AlreadyRegistered(Exception): pass - + class NotRegistered(Exception): pass @@ -20,10 +22,10 @@ class NotRegistered(Exception): class TranslationOptions(object): """ The TranslationOptions object is used to specify the fields to translate. - + The options are registered in combination with a model class at the ``modeltranslation.translator.translator`` instance. - + It caches the content type of the translated model for faster lookup later on. """ @@ -35,59 +37,61 @@ class TranslationOptions(object): def add_localized_fields(model): """ - Monkey patchs the original model class to provide additional fields for - every language. Only do that for fields which are defined in the + Monkey patchs the original model class to provide additional fields for + every language. Only do that for fields which are defined in the translation options of the model. - + Returns a dict mapping the original fieldname to a list containing the names of the localized fields created for the original field. """ localized_fields = dict() translation_opts = translator.get_options_for_model(model) - for field_name in translation_opts.fields: + for field_name in translation_opts.fields: localized_fields[field_name] = list() - for l in settings.LANGUAGES: + for l in settings.LANGUAGES: # 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 + # Check if the model already has a field by that name if hasattr(model, localized_field_name): raise ValueError("Error adding translation field. The model "\ "'%s' already contains a field named '%s'. "\ % (instance.__class__.__name__, localized_field_name)) - + # 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, - TranslationField(model._meta.get_field(field_name), - l[0])) + localized_field = model.add_to_class( \ + localized_field_name, + TranslationField(model._meta.get_field(field_name), l[0])) localized_fields[field_name].append(localized_field_name) - return localized_fields - - + return localized_fields + + #def translated_model_initialized(field_names, instance, **kwargs): - #print "translated_model_initialized instance:", instance, ", field:", field_names + #print "translated_model_initialized instance:", \ + #instance, ", field:", field_names #for field_name in field_names: #initial_val = getattr(instance, field_name) #print " field: %s, initialval: %s" % (field_name, initial_val) - #setattr(instance.__class__, field_name, TranslationFieldDescriptor(field_name, - #initial_val)) - - + #setattr(instance.__class__, field_name, + #TranslationFieldDescriptor(field_name, initial_val)) + + #def translated_model_initializing(sender, args, kwargs, **signal_kwargs): - #print "translated_model_initializing", sender, args, kwargs + #print "translated_model_initializing", sender, args, kwargs #trans_opts = translator.get_options_for_model(sender) #for field_name in trans_opts.fields: #setattr(sender, field_name, TranslationFieldDescriptor(field_name)) - - + + class Translator(object): """ A Translator object encapsulates an instance of a translator. Models are registered with the Translator using the register() method. """ def __init__(self): - self._registry = {} # model_class class -> translation_opts instance + # model_class class -> translation_opts instance + self._registry = {} def register(self, model_or_iterable, translation_opts, **options): """ @@ -95,7 +99,7 @@ class Translator(object): The model(s) should be Model classes, not instances. - If a model is already registered for translation, this will raise + If a model is already registered for translation, this will raise AlreadyRegistered. """ # Don't import the humongous validation code unless required @@ -105,13 +109,14 @@ class Translator(object): validate = lambda model, adminclass: None #if not translation_opts: - #translation_opts = TranslationOptions + #translation_opts = TranslationOptions if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] - + for model in model_or_iterable: if model in self._registry: - raise AlreadyRegistered('The model %s is already registered for translation' % model.__name__) + raise AlreadyRegistered('The model %s is already registered ' + 'for translation' % model.__name__) # If we got **options then dynamically construct a subclass of # translation_opts with those **options. @@ -120,63 +125,67 @@ class Translator(object): # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ - translation_opts = type("%sAdmin" % model.__name__, (translation_opts,), options) + translation_opts = type("%sAdmin" % model.__name__, + (translation_opts,), options) # Validate (which might be a no-op) #validate(translation_opts, model) # Store the translation class associated to the model self._registry[model] = translation_opts - + # Get the content type of the original model and store it on the # translation options for faster lookup later on. - #translation_opts.model_ct = ContentType.objects.get_for_model(model) - - # Add the localized fields to the model and store the names of these - # fields in the model's translation options for faster lookup later - # on. + #translation_opts.model_ct = \ + #ContentType.objects.get_for_model(model) + + # Add the localized fields to the model and store the names of + # these fields in the model's translation options for faster lookup + # later on. translation_opts.localized_fieldnames = add_localized_fields(model) - - # Create a reverse dict mapping the localized_fieldnames to the + + # Create a reverse dict mapping the localized_fieldnames to the # original fieldname rev_dict = dict() - for orig_name, loc_names in translation_opts.localized_fieldnames.items(): + for orig_name, loc_names in \ + translation_opts.localized_fieldnames.items(): for ln in loc_names: rev_dict[ln] = orig_name - - translation_opts.localized_fieldnames_rev = rev_dict - - # print "Applying descriptor field for model %s" % model + + translation_opts.localized_fieldnames_rev = rev_dict + + # print "Applying descriptor field for model %s" % model for field_name in translation_opts.fields: setattr(model, field_name, TranslationFieldDescriptor(field_name)) - - #signals.pre_init.connect(translated_model_initializing, sender=model, weak=False) - + + #signals.pre_init.connect(translated_model_initializing, sender=model, + #weak=False) + def unregister(self, model_or_iterable): """ Unregisters the given model(s). If a model isn't already registered, this will raise NotRegistered. - """ if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model not in self._registry: - raise NotRegistered('The model "%s" is not registered for translation' % model.__name__) + raise NotRegistered('The model "%s" is not registered for ' + 'translation' % model.__name__) del self._registry[model] - + def get_options_for_model(self, model): """ - Returns the translation options for the given ``model``. If the + Returns the translation options for the given ``model``. If the ``model`` is not registered a ``NotRegistered`` exception is raised. - """ try: return self._registry[model] except KeyError: - raise NotRegistered('The model "%s" is not registered for translation' % model.__name__) - + raise NotRegistered('The model "%s" is not registered for ' + 'translation' % model.__name__) + # This global object represents the singleton translator object translator = Translator() diff --git a/modeltranslation/utils.py b/modeltranslation/utils.py index e6e58b7..aeb57d1 100644 --- a/modeltranslation/utils.py +++ b/modeltranslation/utils.py @@ -5,11 +5,12 @@ from django.core.exceptions import ValidationError from django.contrib.contenttypes.models import ContentType from django.utils.translation import get_language as _get_language + def get_language(): """ Return an active language code that is guaranteed to be in settings.LANGUAGES (Django does not seem to guarantee this for us.) - + """ lang = _get_language() available_languages = [l[0] for l in settings.LANGUAGES] @@ -25,6 +26,10 @@ def get_translation_fields(field): return [build_localized_fieldname(field, l[0]) for l in settings.LANGUAGES] +def build_localized_fieldname(field_name, lang): + return '%s_%s' % (field_name, lang.replace('-', '_')) + + class TranslationFieldDescriptor(object): """A descriptor used for the original translated field.""" def __init__(self, name, initial_val=""): @@ -32,42 +37,40 @@ class TranslationFieldDescriptor(object): The ``name`` is the name of the field (which is not available in the descriptor by default - this is Python behaviour). """ - self.name = name + self.name = name self.val = initial_val - def __set__(self, instance, value): - # print "Descriptor.__set__%s %s %s.%s: %s" % (id(instance), id(self), type(instance), self.name, value) + def __set__(self, instance, value): lang = get_language() loc_field_name = build_localized_fieldname(self.name, lang) - - # also update the translation field of the current language + # also update the translation field of the current language setattr(instance, loc_field_name, value) - # update the original field via the __dict__ to prevent calling the # descriptor instance.__dict__[self.name] = value - - def __get__(self, instance, owner): - # print "Descriptor.__get__%s %s %s.%s: %s" % (id(instance), id(self), type(instance), self.name, self.val) - if not instance: - raise ValueError(u"Translation field '%s' can only be "\ - "accessed via an instance not via "\ - "a class." % self.name) - - lang = get_language() - loc_field_name = build_localized_fieldname(self.name, lang) - if hasattr(instance, loc_field_name): - return getattr(instance, loc_field_name) or instance.__dict__[self.name] - return instance.__dict__[self.name] - -#def create_model(name, fields=None, app_label='', module='', options=None, admin_opts=None): + def __get__(self, instance, owner): + if not instance: + raise ValueError(u"Translation field '%s' can only be " + "accessed via an instance not via " + "a class." % self.name) + lang = get_language() + loc_field_name = build_localized_fieldname(self.name, lang) + if hasattr(instance, loc_field_name): + return getattr(instance, loc_field_name) or \ + instance.__dict__[self.name] + return instance.__dict__[self.name] + + +#def create_model(name, fields=None, app_label='', module='', options=None, + #admin_opts=None): #""" #Create specified model. #This is taken from http://code.djangoproject.com/wiki/DynamicModels #""" #class Meta: - ## Using type('Meta', ...) gives a dictproxy error during model creation + ## Using type('Meta', ...) gives a dictproxy error during model + ## creation #pass #if app_label: @@ -98,26 +101,23 @@ class TranslationFieldDescriptor(object): #admin.site.register(model, Admin) #return model - - + + def copy_field(field): """ - Instantiate a new field, with all of the values from the old one, except the - to and to_field in the case of related fields. - + Instantiate a new field, with all of the values from the old one, except + the to and to_field in the case of related fields. + This taken from http://www.djangosnippets.org/snippets/442/ - - """ - base_kw = dict([(n, getattr(field, n, '_null')) for n in models.fields.Field.__init__.im_func.func_code.co_varnames]) + """ + base_kw = dict([(n, getattr(field, n, '_null')) for n in \ + models.fields.Field.__init__.im_func.func_code.co_varnames]) if isinstance(field, models.fields.related.RelatedField): rel = base_kw.get('rel') - rel_kw = dict([(n, getattr(rel, n, '_null')) for n in rel.__init__.im_func.func_code.co_varnames]) + rel_kw = dict([(n, getattr(rel, n, '_null')) for n in \ + rel.__init__.im_func.func_code.co_varnames]) if isinstance(field, models.fields.related.ForeignKey): base_kw['to_field'] = rel_kw.pop('field_name') base_kw.update(rel_kw) - base_kw.pop('self') + base_kw.pop('self') return field.__class__(**base_kw) - - -def build_localized_fieldname(field_name, lang): - return '%s_%s' % (field_name, lang.replace('-', '_'))