mirror of
https://github.com/Hopiu/django-modeltranslation.git
synced 2026-05-25 12:43:45 +00:00
Implement ForeignKey support (does not support reverse relations)
This commit is contained in:
parent
ea0e2db689
commit
420e3b6c52
4 changed files with 89 additions and 10 deletions
|
|
@ -25,6 +25,7 @@ SUPPORTED_FIELDS = (
|
|||
fields.TimeField,
|
||||
fields.files.FileField,
|
||||
fields.files.ImageField,
|
||||
fields.related.ForeignKey,
|
||||
)
|
||||
try:
|
||||
SUPPORTED_FIELDS += (fields.GenericIPAddressField,) # Django 1.4+ only
|
||||
|
|
@ -50,6 +51,8 @@ def create_translation_field(model, field_name, lang):
|
|||
if not (isinstance(field, SUPPORTED_FIELDS) or cls_name in mt_settings.CUSTOM_FIELDS):
|
||||
raise ImproperlyConfigured(
|
||||
'%s is not supported by modeltranslation.' % cls_name)
|
||||
if isinstance(field, fields.related.ForeignKey) and field.rel.related_name != '+':
|
||||
raise ImproperlyConfigured('Translated ForeignKey fields must use related_name="+"')
|
||||
translation_class = field_factory(field.__class__)
|
||||
return translation_class(translated_field=field, language=lang)
|
||||
|
||||
|
|
@ -127,8 +130,10 @@ class TranslationField(object):
|
|||
|
||||
def get_attname_column(self):
|
||||
attname = self.get_attname()
|
||||
column = build_localized_fieldname(
|
||||
self.translated_field.db_column or self.translated_field.name, self.language) or attname
|
||||
if self.translated_field.db_column:
|
||||
column = build_localized_fieldname(self.translated_field.db_column)
|
||||
else:
|
||||
column = attname
|
||||
return attname, column
|
||||
|
||||
def south_field_triple(self):
|
||||
|
|
@ -137,8 +142,12 @@ class TranslationField(object):
|
|||
"""
|
||||
# We'll just introspect the _actual_ field.
|
||||
from south.modelsinspector import introspector
|
||||
field_class = '%s.%s' % (self.translated_field.__class__.__module__,
|
||||
self.translated_field.__class__.__name__)
|
||||
try:
|
||||
# Check if the field provides its own 'field_class':
|
||||
field_class = self.translated_field.south_field_triple()[0]
|
||||
except AttributeError:
|
||||
field_class = '%s.%s' % (self.translated_field.__class__.__module__,
|
||||
self.translated_field.__class__.__name__)
|
||||
args, kwargs = introspector(self)
|
||||
# That's our definition!
|
||||
return (field_class, args, kwargs)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ except ImportError:
|
|||
# so we'll just pass in None.
|
||||
request = None
|
||||
|
||||
# How much models are registered for tests.
|
||||
TEST_MODELS = 22
|
||||
# How many models are registered for tests.
|
||||
TEST_MODELS = 23
|
||||
|
||||
|
||||
class reload_override_settings(override_settings):
|
||||
|
|
@ -619,6 +619,64 @@ class FileFieldsTest(ModeltranslationTestBase):
|
|||
inst.image_de.delete()
|
||||
|
||||
|
||||
class ForeignKeyFieldsTest(ModeltranslationTestBase):
|
||||
|
||||
def test_translated_models(self):
|
||||
field_names = dir(models.ForeignKeyModel())
|
||||
self.failUnless('id' in field_names)
|
||||
for f in ('test', 'test_de', 'test_en', 'optional', 'optional_en', 'optional_de'):
|
||||
self.failUnless(f in field_names)
|
||||
self.failUnless('%s_id' % f in field_names)
|
||||
|
||||
def test_db_column_names(self):
|
||||
meta = models.ForeignKeyModel._meta
|
||||
|
||||
# Make sure the correct database columns always get used:
|
||||
attname, col = meta.get_field('test').get_attname_column()
|
||||
self.failUnlessEqual(attname, 'test_id')
|
||||
self.failUnlessEqual(attname, col)
|
||||
|
||||
attname, col = meta.get_field('test_en').get_attname_column()
|
||||
self.failUnlessEqual(attname, 'test_en_id')
|
||||
self.failUnlessEqual(attname, col)
|
||||
|
||||
attname, col = meta.get_field('test_de').get_attname_column()
|
||||
self.failUnlessEqual(attname, 'test_de_id')
|
||||
self.failUnlessEqual(attname, col)
|
||||
|
||||
def test_translated_models_instance(self):
|
||||
test_inst1 = models.TestModel(title_en='title1_en', title_de='title1_de')
|
||||
test_inst1.save()
|
||||
test_inst2 = models.TestModel(title_en='title2_en', title_de='title2_de')
|
||||
test_inst2.save()
|
||||
inst = models.ForeignKeyModel()
|
||||
|
||||
trans_real.activate("de")
|
||||
inst.test = test_inst1
|
||||
inst.optional = None
|
||||
|
||||
trans_real.activate("en")
|
||||
inst.optional = test_inst2
|
||||
inst.save()
|
||||
|
||||
trans_real.activate("de")
|
||||
self.failUnlessEqual(inst.test.title, 'title1_de')
|
||||
self.failUnlessEqual(inst.test_de_id, test_inst1.pk)
|
||||
self.failUnlessEqual(inst.test_de.title, 'title1_de')
|
||||
self.failUnlessEqual(inst.optional, None)
|
||||
|
||||
# Test fallbacks:
|
||||
trans_real.activate("en")
|
||||
with default_fallback():
|
||||
self.failUnlessEqual(inst.test.pk, test_inst1.pk)
|
||||
self.failUnlessEqual(inst.test.title, 'title1_en')
|
||||
|
||||
# Test English:
|
||||
self.failUnlessEqual(inst.optional.title, 'title2_en')
|
||||
self.failUnlessEqual(inst.optional_en_id, test_inst2.pk)
|
||||
self.failUnlessEqual(inst.optional_en.title, 'title2_en')
|
||||
|
||||
|
||||
class OtherFieldsTest(ModeltranslationTestBase):
|
||||
def test_translated_models(self):
|
||||
inst = models.OtherFieldsModel.objects.create()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ class FileFieldsModel(models.Model):
|
|||
file = models.FileField(upload_to='modeltranslation_tests', null=True, blank=True)
|
||||
image = models.ImageField(upload_to='modeltranslation_tests', null=True, blank=True)
|
||||
|
||||
########## Foreign Key fields testing
|
||||
|
||||
class ForeignKeyModel(models.Model):
|
||||
test = models.ForeignKey(TestModel, null=True, related_name="+")
|
||||
optional = models.ForeignKey(TestModel, blank=True, null=True, related_name="+")
|
||||
|
||||
########## Custom fields testing
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ from django.utils.translation import ugettext_lazy
|
|||
|
||||
from modeltranslation.translator import translator, TranslationOptions
|
||||
from modeltranslation.tests.models import (
|
||||
TestModel, FallbackModel, FallbackModel2, FileFieldsModel, OtherFieldsModel, DescriptorModel,
|
||||
AbstractModelA, AbstractModelB, Slugged, MetaData, Displayable, Page, RichText, RichTextPage,
|
||||
MultitableModelA, MultitableModelB, MultitableModelC, ManagerTestModel, CustomManagerTestModel,
|
||||
CustomManager2TestModel, GroupFieldsetsModel, NameModel)
|
||||
TestModel, FallbackModel, FallbackModel2, FileFieldsModel, ForeignKeyModel, OtherFieldsModel,
|
||||
DescriptorModel, AbstractModelA, AbstractModelB, Slugged, MetaData, Displayable, Page,
|
||||
RichText, RichTextPage, MultitableModelA, MultitableModelB, MultitableModelC, ManagerTestModel,
|
||||
CustomManagerTestModel, CustomManager2TestModel, GroupFieldsetsModel, NameModel)
|
||||
|
||||
|
||||
class TestTranslationOptions(TranslationOptions):
|
||||
|
|
@ -35,6 +35,13 @@ class FileFieldsModelTranslationOptions(TranslationOptions):
|
|||
translator.register(FileFieldsModel, FileFieldsModelTranslationOptions)
|
||||
|
||||
|
||||
########## Foreign Key fields testing
|
||||
|
||||
class ForeignKeyModelTranslationOptions(TranslationOptions):
|
||||
fields = ('test', 'optional',)
|
||||
translator.register(ForeignKeyModel, ForeignKeyModelTranslationOptions)
|
||||
|
||||
|
||||
########## Custom fields testing
|
||||
|
||||
class OtherFieldsModelTranslationOptions(TranslationOptions):
|
||||
|
|
|
|||
Loading…
Reference in a new issue