diff --git a/modeltranslation/fields.py b/modeltranslation/fields.py index 7ef596c..56bd285 100644 --- a/modeltranslation/fields.py +++ b/modeltranslation/fields.py @@ -270,6 +270,15 @@ class TranslationFieldDescriptor(object): loc_field_name = build_localized_fieldname(self.field.name, get_language()) setattr(instance, loc_field_name, value) + def meaningful_value(self, val, undefined): + """ + Check if val is considered non-empty. + """ + if isinstance(val, fields.files.FieldFile): + return val.name and not ( + isinstance(undefined, fields.files.FieldFile) and val == undefined) + return val is not None and val != undefined + def __get__(self, instance, owner): """ Returns value from the translation field for the current language, or @@ -287,13 +296,20 @@ class TranslationFieldDescriptor(object): for lang in langs: loc_field_name = build_localized_fieldname(self.field.name, lang) val = getattr(instance, loc_field_name, None) - if val is not None and val != undefined: + if self.meaningful_value(val, undefined): return val if mt_settings.ENABLE_FALLBACKS and self.fallback_value is not NONE: return self.fallback_value else: if default is NONE: default = self.field.get_default() + # Some fields like FileField behave strange, as their get_default() doesn't return + # instance of attr_class, but rather None or ''. + # Normally this case is handled in the descriptor, but since we have overridden it, we + # must mock it up. + if (isinstance(self.field, fields.files.FileField) and + not isinstance(default, self.field.attr_class)): + return self.field.attr_class(instance, self.field, default) return default diff --git a/modeltranslation/tests/__init__.py b/modeltranslation/tests/__init__.py index 9249104..ef59e84 100644 --- a/modeltranslation/tests/__init__.py +++ b/modeltranslation/tests/__init__.py @@ -671,6 +671,36 @@ class FileFieldsTest(ModeltranslationTestBase): inst.file_de.delete() inst.image_de.delete() + def test_empty_field(self): + from django.db.models.fields.files import FieldFile + inst = models.FileFieldsModel() + self.assertIsInstance(inst.file, FieldFile) + self.assertIsInstance(inst.file2, FieldFile) + inst.save() + inst = models.FileFieldsModel.objects.all()[0] + self.assertIsInstance(inst.file, FieldFile) + self.assertIsInstance(inst.file2, FieldFile) + + def test_fallback(self): + from django.db.models.fields.files import FieldFile + with reload_override_settings(MODELTRANSLATION_FALLBACK_LANGUAGES=('en',)): + self.assertEqual(get_language(), 'de') + inst = models.FileFieldsModel() + inst.file_de = '' + inst.file_en = 'foo' + inst.file2_de = '' + inst.file2_en = 'bar' + self.assertIsInstance(inst.file, FieldFile) + self.assertIsInstance(inst.file2, FieldFile) + self.assertEqual(inst.file.name, 'foo') + self.assertEqual(inst.file2.name, 'bar') + inst.save() + inst = models.FileFieldsModel.objects.all()[0] + self.assertIsInstance(inst.file, FieldFile) + self.assertIsInstance(inst.file2, FieldFile) + self.assertEqual(inst.file.name, 'foo') + self.assertEqual(inst.file2.name, 'bar') + class ForeignKeyFieldsTest(ModeltranslationTestBase): @classmethod diff --git a/modeltranslation/tests/models.py b/modeltranslation/tests/models.py index daa6c89..3116ab6 100644 --- a/modeltranslation/tests/models.py +++ b/modeltranslation/tests/models.py @@ -52,6 +52,7 @@ class FallbackModel2(models.Model): class FileFieldsModel(models.Model): title = models.CharField(ugettext_lazy('title'), max_length=255) file = models.FileField(upload_to='modeltranslation_tests', null=True, blank=True) + file2 = models.FileField(upload_to='modeltranslation_tests') image = models.ImageField(upload_to='modeltranslation_tests', null=True, blank=True) diff --git a/modeltranslation/tests/translation.py b/modeltranslation/tests/translation.py index 60180b4..c817a89 100644 --- a/modeltranslation/tests/translation.py +++ b/modeltranslation/tests/translation.py @@ -46,7 +46,7 @@ translator.register(FallbackModel2, FallbackModel2TranslationOptions) ########## File fields testing class FileFieldsModelTranslationOptions(TranslationOptions): - fields = ('title', 'file', 'image',) + fields = ('title', 'file', 'file2', 'image',) translator.register(FileFieldsModel, FileFieldsModelTranslationOptions)