def test_instance_wrong_translation(self): # no language enforced form = NormalForm(instance=Normal.objects.language('en').get( pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['en']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['en'], form.as_p()) self.assertEqual( get_cached_translation(form.instance).language_code, 'en') # enforce japanese language Form = translatable_modelform_factory('ja', Normal, form=NormalForm) form = Form(instance=Normal.objects.language('en').get( pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['ja']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['ja'], form.as_p()) self.assertEqual( get_cached_translation(form.instance).language_code, 'en')
def test_instance_untranslated(self): # no language enforced, should load anyway with translation.override('en'): form = NormalForm(instance=Normal.objects.untranslated().get( pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['en']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['en'], form.as_p()) self.assertIs(get_cached_translation(form.instance), None) # enforce japanese language with translation.override('en'): Form = translatable_modelform_factory('ja', Normal, form=NormalForm) form = Form(instance=Normal.objects.untranslated().get( pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['ja']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['ja'], form.as_p()) self.assertIs(get_cached_translation(form.instance), None)
def test_translated_attribute_set(self): """ Translated attribute set behaviors """ # Set translated attribute with a translation loaded obj = Normal.objects.language("en").get(pk=self.normal_id[1]) trans = get_cached_translation(obj) with self.assertNumQueries(0): obj.translated_field = 'foo' self.assertNotIn('translated_field', obj.__dict__) self.assertEqual(trans.__dict__['translated_field'], 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is false obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(0): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': False}): self.assertRaises(AttributeError, setattr, obj, 'translated_field', 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is true and one exists obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': True}), translation.override('ja'): obj.translated_field = 'foo' trans = get_cached_translation(obj) self.assertNotIn('translated_field', obj.__dict__) self.assertEqual(trans.__dict__['translated_field'], 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is true but none exists obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': True}), translation.override('fr'): self.assertRaises(AttributeError, setattr, obj, 'translated_field', 'foo')
def test_translated_attribute_set(self): """ Translated attribute set behaviors """ # Set translated attribute with a translation loaded obj = Normal.objects.language("en").get(pk=self.normal_id[1]) trans = get_cached_translation(obj) with self.assertNumQueries(0): obj.translated_field = 'foo' self.assertNotIn('translated_field', obj.__dict__) self.assertEqual(trans.__dict__['translated_field'], 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is false obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(0): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': False}): self.assertRaises(AttributeError, setattr, obj, 'translated_field', 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is true and one exists obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': True }), translation.override('ja'): obj.translated_field = 'foo' trans = get_cached_translation(obj) self.assertNotIn('translated_field', obj.__dict__) self.assertEqual(trans.__dict__['translated_field'], 'foo') # Set translated attribute without a translation loaded, AUTOLOAD is true but none exists obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): with self.settings(HVAD={'AUTOLOAD_TRANSLATIONS': True }), translation.override('fr'): self.assertRaises(AttributeError, setattr, obj, 'translated_field', 'foo')
def test_defer_translated(self): with self.assertNumQueries(1): qs = list(Normal.objects.language('en').defer('translated_field')) obj = qs[0] self.assertIn('shared_field', obj.__dict__) self.assertNotIn('translated_field', get_cached_translation(obj).__dict__) with self.assertNumQueries(1): self.assertEqual(obj.translated_field, NORMAL[1].translated_field['en']) self.assertIn('translated_field', get_cached_translation(obj).__dict__)
def test_defer_chained(self): """ Mutiple defer calls are cumulative, defer(None) resets everything """ qs = Normal.objects.language('en').defer('shared_field').defer('translated_field') with self.assertNumQueries(1): obj = list(qs)[0] self.assertNotIn('shared_field', obj.__dict__) self.assertNotIn('translated_field', get_cached_translation(obj).__dict__) qs = qs.defer(None) with self.assertNumQueries(1): obj = list(qs)[0] self.assertIn('shared_field', obj.__dict__) self.assertIn('translated_field', get_cached_translation(obj).__dict__)
def test_defer_chained(self): """ Mutiple defer calls are cumulative, defer(None) resets everything """ qs = Normal.objects.language('en').defer('shared_field').defer( 'translated_field') with self.assertNumQueries(1): obj = list(qs)[0] self.assertNotIn('shared_field', obj.__dict__) self.assertNotIn('translated_field', get_cached_translation(obj).__dict__) qs = qs.defer(None) with self.assertNumQueries(1): obj = list(qs)[0] self.assertIn('shared_field', obj.__dict__) self.assertIn('translated_field', get_cached_translation(obj).__dict__)
def clean(self): super(BaseTranslationFormSet, self).clean() # Trigger combined instance validation master = self.instance stashed = get_cached_translation(master) for form in self.forms: form.instance.master = master combined = combine(form.instance, master.__class__) exclusions = form._get_validation_exclusions() # fields from the shared model should not be validated exclusions.extend(f.name for f in combined._meta.fields) try: if django.VERSION >= (1, 6): combined.full_clean(exclude=exclusions, validate_unique=form._validate_unique) else: combined.full_clean(exclude=exclusions) except ValidationError as e: form._update_errors(e) if stashed is None: delattr(master, master._meta.translations_cache) else: setattr(master, master._meta.translations_cache, stashed) # Validate that at least one translation exists forms_to_delete = self.deleted_forms valid = [((form.instance and form.instance.pk is not None) or (form.is_valid() and form.has_changed())) and not form in forms_to_delete for form in self.forms] if valid.count(True) < 1: raise ValidationError(_('At least one translation must be provided'), code='notranslation')
def save(self, *args, **skwargs): veto_names = ('pk', 'master', 'master_id', self._meta.translations_model._meta.pk.name) translations_opts = self._meta.translations_model._meta translation = get_cached_translation(self) tkwargs = skwargs.copy() # split update_fields in shared/translated fields update_fields = skwargs.get('update_fields') if update_fields is not None: supdate, tupdate = [], [] for name in update_fields: if name in veto_names: supdate.append(name) else: try: translations_opts.get_field(name) except FieldDoesNotExist: supdate.append(name) else: tupdate.append(name) skwargs['update_fields'], tkwargs['update_fields'] = supdate, tupdate # save share and translated model in a single transaction if update_fields is None or skwargs['update_fields']: super(TranslatableModel, self).save(*args, **skwargs) if (update_fields is None or tkwargs['update_fields']) and translation is not None: if translation.pk is None and update_fields: del tkwargs['update_fields'] # allow new translations translation.master = self translation.save(*args, **tkwargs)
def save(self, *args, **skwargs): translation_model = self._meta.translations_model translation = get_cached_translation(self) tkwargs = skwargs.copy() # split update_fields in shared/translated fields update_fields = skwargs.get('update_fields') if update_fields is not None: supdate, tupdate = [], [] for name in update_fields: if name in self._translated_field_names and not name in ( 'id', 'master_id', 'master'): tupdate.append(name) else: supdate.append(name) skwargs['update_fields'], tkwargs[ 'update_fields'] = supdate, tupdate # save share and translated model in a single transaction if update_fields is None or skwargs['update_fields']: super(TranslatableModel, self).save(*args, **skwargs) if (update_fields is None or tkwargs['update_fields']) and translation is not None: if translation.pk is None and update_fields: del tkwargs['update_fields'] # allow new translations translation.master = self translation.save(*args, **tkwargs)
def clean(self): super(BaseTranslationFormSet, self).clean() # Trigger combined instance validation master = self.instance stashed = get_cached_translation(master) for form in self.forms: set_cached_translation(master, form.instance) exclusions = form._get_validation_exclusions() # fields from the shared model should not be validated exclusions.extend(f.name for f in master._meta.fields) try: master.clean() except ValidationError as e: form._update_errors(e) set_cached_translation(master, stashed) # Validate that at least one translation exists forms_to_delete = self.deleted_forms provided = [ form for form in self.forms if (getattr(form.instance, 'pk', None) is not None or form.has_changed()) and not form in forms_to_delete ] if len(provided) < 1: raise ValidationError( _('At least one translation must be provided'), code='notranslation')
def clean_fields(self, exclude=None): super(TranslatableModel, self).clean_fields(exclude=exclude) translation = get_cached_translation(self) if translation is not None: translation.clean_fields( exclude=exclude + ['id', 'master', 'master_id', 'language_code'])
def save(self, commit=True): if self.instance.pk is None: fail_message = 'created' new = True else: fail_message = 'changed' new = False super(TranslatableModelForm, self).save(True) trans_model = self.instance._meta.translations_model language_code = self.cleaned_data.get('language_code', get_language()) if not new: trans = get_cached_translation(self.instance) if not trans or trans.language_code != language_code: try: trans = get_translation(self.instance, language_code) except trans_model.DoesNotExist: trans = trans_model() else: trans = trans_model() trans.language_code = language_code trans.master = self.instance trans = save_instance(self, trans, self._meta.fields, fail_message, commit, construct=True) return combine(trans, self.Meta.model)
def save(self, commit=True): if self.instance.pk is None: fail_message = 'created' new = True else: fail_message = 'changed' new = False if self.errors: opts = instance._meta raise ValueError("The %s could not be %s because the data didn't" " validate." % (opts.object_name, fail_message)) trans_model = self.instance._meta.translations_model language_code = self.cleaned_data.get('language_code', get_language()) if not new: trans = get_cached_translation(self.instance) if not trans or trans.language_code != language_code: try: trans = get_translation(self.instance, language_code) except trans_model.DoesNotExist: trans = trans_model() else: trans = trans_model() trans = construct_instance(self, trans, self._meta.fields) trans.language_code = language_code trans.master = self.instance self.instance = combine(trans, self.Meta.model) super(TranslatableModelForm, self).save(commit=commit) return self.instance
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList, label_suffix=':', empty_permitted=False, instance=None): """ """ opts = self._meta model_opts = opts.model._meta object_data = {} language = getattr(self, 'language', get_language()) if instance is not None: trans = get_cached_translation(instance) if not trans or trans.language_code != language: try: trans = get_translation(instance, language) except model_opts.translations_model.DoesNotExist: trans = None if trans: object_data = model_to_dict(trans, opts.fields, opts.exclude) # Dirty hack that swaps the id from the translation id, to the master id # This is necessary, because we in this case get the untranslated instance, # and thereafter get the correct translation on save. if "id" in object_data: object_data["id"] = trans.master.id if initial is not None: object_data.update(initial) initial = object_data super(TranslatableModelForm, self).__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, instance)
def clean(self): super(BaseTranslationFormSet, self).clean() # Trigger combined instance validation master = self.instance stashed = get_cached_translation(master) for form in self.forms: set_cached_translation(master, form.instance) exclusions = form._get_validation_exclusions() # fields from the shared model should not be validated exclusions.extend(f.name for f in master._meta.fields) try: master.clean() except ValidationError as e: form._update_errors(e) set_cached_translation(master, stashed) # Validate that at least one translation exists forms_to_delete = self.deleted_forms provided = [form for form in self.forms if (getattr(form.instance, 'pk', None) is not None or form.has_changed()) and not form in forms_to_delete] if len(provided) < 1: raise ValidationError(_('At least one translation must be provided'), code='notranslation')
def __init__( self, data=None, files=None, auto_id="id_%s", prefix=None, initial=None, error_class=ErrorList, label_suffix=":", empty_permitted=False, instance=None, ): opts = self._meta model_opts = opts.model._meta object_data = {} language = getattr(self, "language", get_language()) if instance is not None: trans = get_cached_translation(instance) if not trans: try: trans = get_translation(instance, language) except model_opts.translations_model.DoesNotExist: trans = None if trans: object_data = model_to_dict(trans, opts.fields, opts.exclude) if initial is not None: object_data.update(initial) initial = object_data super(TranslatableModelForm, self).__init__( data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance )
def save(self, commit=True): if self.instance.pk is None: fail_message = 'created' new = True else: fail_message = 'changed' new = False if self.errors: opts = self.instance._meta raise ValueError("The %s could not be %s because the data didn't" " validate." % (opts.object_name, fail_message)) trans_model = self.instance._meta.translations_model language_code = self.cleaned_data.get('language_code', get_language()) if not new: trans = get_cached_translation(self.instance) if not trans or trans.language_code != language_code: try: trans = get_translation(self.instance, language_code) except trans_model.DoesNotExist: trans = trans_model() else: trans = trans_model() trans = construct_instance(self, trans, self._meta.fields) trans.language_code = language_code trans.master = self.instance self.instance = combine(trans, self.Meta.model) super(TranslatableModelForm, self).save(commit=commit) return self.instance
def save(self, *args, **skwargs): veto_names = ('pk', 'master', 'master_id', self._meta.translations_model._meta.pk.name) translations_opts = self._meta.translations_model._meta translation = get_cached_translation(self) tkwargs = skwargs.copy() # split update_fields in shared/translated fields update_fields = skwargs.get('update_fields') if update_fields is not None: supdate, tupdate = [], [] for name in update_fields: if name in veto_names: supdate.append(name) else: try: translations_opts.get_field(name) except FieldDoesNotExist: supdate.append(name) else: tupdate.append(name) skwargs['update_fields'], tkwargs[ 'update_fields'] = supdate, tupdate # save share and translated model in a single transaction if update_fields is None or skwargs['update_fields']: super(TranslatableModel, self).save(*args, **skwargs) if (update_fields is None or tkwargs['update_fields']) and translation is not None: if translation.pk is None and update_fields: del tkwargs['update_fields'] # allow new translations translation.master = self translation.save(*args, **tkwargs)
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=ErrorList, label_suffix=':', empty_permitted=False, instance=None): opts = self._meta model_opts = opts.model._meta object_data = {} language = getattr(self, 'language', get_language()) if instance is not None: trans = get_cached_translation(instance) if not trans: try: trans = get_translation(instance, language) except model_opts.translations_model.DoesNotExist: trans = None if trans: object_data = model_to_dict(trans, opts.fields, opts.exclude) if initial is not None: object_data.update(initial) initial = object_data super(TranslatableModelForm, self).__init__(data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance)
def to_representation(self, instance): ''' Combine each translation in turn so the serializer has a full object ''' result = {} stashed = get_cached_translation(instance) for translation in getattr(instance, self.source).all(): set_cached_translation(instance, translation) result[translation.language_code] = self.child.to_representation(instance) set_cached_translation(instance, stashed) return result
def to_representation(self, instance): ''' Combine each translation in turn so the serializer has a full object ''' result = {} stashed = get_cached_translation(instance) for translation in getattr(instance, self.source).all(): set_cached_translation(instance, translation) result[translation.language_code] = self.child.to_representation( instance) set_cached_translation(instance, stashed) return result
def translation(self, instance): translation = get_cached_translation(instance) if translation is None: try: translation = get_translation(instance) except self.opts.translations_model.DoesNotExist: language_code = instance.default_language translation = instance.translations.get(language_code = language_code) set_cached_translation(instance, translation) return translation
def translation(self, instance): translation = get_cached_translation(instance) if translation is None: try: translation = get_translation(instance) except self.opts.translations_model.DoesNotExist: raise self._NoTranslationError('Accessing a translated field requires that ' 'the instance has a translation loaded, or a ' 'valid translation in current language (%s) ' 'loadable from the database' % get_language()) set_cached_translation(instance, translation) return translation
def test_instance_wrong_translation(self): # no language enforced form = NormalForm(instance=Normal.objects.language('en').get(pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['en']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['en'], form.as_p()) self.assertEqual(get_cached_translation(form.instance).language_code, 'en') # enforce japanese language Form = translatable_modelform_factory('ja', Normal, form=NormalForm) form = Form(instance=Normal.objects.language('en').get(pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['ja']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['ja'], form.as_p()) self.assertEqual(get_cached_translation(form.instance).language_code, 'en')
def test_custom_base_model(self): class CustomTranslation(models.Model): def test(self): return 'foo' class Meta: abstract = True class CustomBaseModel(TranslatableModel): translations = TranslatedFields( base_class=CustomTranslation, tfield=models.CharField(max_length=250), ) obj = CustomBaseModel(language_code='en') self.assertTrue(issubclass(CustomBaseModel._meta.translations_model, CustomTranslation)) self.assertEqual(get_cached_translation(obj).test(), 'foo')
def test_instance_untranslated(self): # no language enforced, should load anyway with translation.override('en'): form = NormalForm(instance=Normal.objects.untranslated().get(pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['en']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['en'], form.as_p()) self.assertIs(get_cached_translation(form.instance), None) # enforce japanese language with translation.override('en'): Form = translatable_modelform_factory('ja', Normal, form=NormalForm) form = Form(instance=Normal.objects.untranslated().get(pk=self.normal_id[1])) self.assertFalse(form.is_valid()) self.assertCountEqual(form.initial, ['shared_field', 'translated_field']) self.assertEqual(form.initial['shared_field'], NORMAL[1].shared_field) self.assertEqual(form.initial['translated_field'], NORMAL[1].translated_field['ja']) self.assertIn('value="%s"' % NORMAL[1].shared_field, form.as_p()) self.assertIn('value="%s"' % NORMAL[1].translated_field['ja'], form.as_p()) self.assertIs(get_cached_translation(form.instance), None)
def _save_translation(self, form, commit=True): obj = form.save(commit=False) assert isinstance(obj, BaseTranslationModel) if commit: # We need to trigger custom save actions on the combined model master = self.instance stashed = get_cached_translation(master) obj.master = master combined = combine(obj, master.__class__) combined.save() if hasattr(combined, 'save_m2m'): # cannot happen, but feature combined.save_m2m() # could be added, be ready if stashed is None: delattr(master, master._meta.translations_cache) else: setattr(master, master._meta.translations_cache, stashed) return obj
def to_representation(self, instance): """ Nested serializer gets the full object, but some field serializers need the actual model their data lives in, that is, the translation. We detect it here. """ translation = get_cached_translation(instance) ret = OrderedDict() for field in self._readable_fields: try: try: attribute = field.get_attribute(instance) except (WrongManager, FieldDoesNotExist): attribute = field.get_attribute(translation) except SkipField: continue if attribute is None: ret[field.field_name] = None else: ret[field.field_name] = field.to_representation(attribute) return ret
def get_slug_in_language(record, language): if not record: return None # possibly no need to hit db, try cache if HVAD_VERSION >= (2, 0, 0): if get_cached_translation(record) and language == record.language_code: return getattr(record.translations.active, 'slug', None) else: if hasattr(record, record._meta.translations_cache ) and language == record.language_code: return record.lazy_translation_getter('slug') try: translation = get_translation(record, language_code=language) except ObjectDoesNotExist: return None else: return translation.slug
def test_custom_base_model(self): class CustomTranslation(models.Model): def test(self): return 'foo' class Meta: abstract = True class CustomBaseModel(TranslatableModel): translations = TranslatedFields( base_class=CustomTranslation, tfield=models.CharField(max_length=250), ) obj = CustomBaseModel(language_code='en') self.assertTrue( issubclass(CustomBaseModel._meta.translations_model, CustomTranslation)) self.assertEqual(get_cached_translation(obj).test(), 'foo')
def clean(self): super(BaseTranslationFormSet, self).clean() # Trigger combined instance validation master = self.instance stashed = get_cached_translation(master) for form in self.forms: form.instance.master = master combined = combine(form.instance, master.__class__) exclusions = form._get_validation_exclusions() # fields from the shared model should not be validated exclusions.extend(f.name for f in combined._meta.fields) try: if django.VERSION >= (1, 6): combined.full_clean(exclude=exclusions, validate_unique=form._validate_unique) else: combined.full_clean(exclude=exclusions) except ValidationError as e: form._update_errors(e) if stashed is None: delattr(master, master._meta.translations_cache) else: setattr(master, master._meta.translations_cache, stashed) # Validate that at least one translation exists forms_to_delete = self.deleted_forms provided = [ form for form in self.forms if (getattr(form.instance, 'pk', None) is not None or form.has_changed()) and not form in forms_to_delete ] if len(provided) < 1: raise ValidationError( _('At least one translation must be provided'), code='notranslation')
def save(self, *args, **skwargs): translation_model = self._meta.translations_model translation = get_cached_translation(self) tkwargs = skwargs.copy() # split update_fields in shared/translated fields update_fields = skwargs.get('update_fields') if update_fields is not None: supdate, tupdate = [], [] for name in update_fields: if name in self._translated_field_names and not name in ('id', 'master_id', 'master'): tupdate.append(name) else: supdate.append(name) skwargs['update_fields'], tkwargs['update_fields'] = supdate, tupdate # save share and translated model in a single transaction if update_fields is None or skwargs['update_fields']: super(TranslatableModel, self).save(*args, **skwargs) if (update_fields is None or tkwargs['update_fields']) and translation is not None: if translation.pk is None and update_fields: del tkwargs['update_fields'] # allow new translations translation.master = self translation.save(*args, **tkwargs)
def test_get_cached_translation(self): obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(0): self.assertIs(get_cached_translation(obj), None) self.assertFalse(hasattr(obj, obj._meta.translations_cache)) obj.translate('sr') self.assertIsNot(get_cached_translation(obj), None) self.assertEqual(get_cached_translation(obj).language_code, 'sr') old = set_cached_translation(obj, obj.translations.get_language('ja')) with self.assertNumQueries(0): self.assertEqual(old.language_code, 'sr') self.assertEqual(obj.language_code, 'ja') self.assertEqual(get_cached_translation(obj).language_code, 'ja') set_cached_translation(obj, None) self.assertIs(get_cached_translation(obj), None) self.assertFalse(hasattr(obj, obj._meta.translations_cache)) obj = Normal.objects.language('en').get(pk=self.normal_id[1]) with self.assertNumQueries(0): self.assertEqual(get_cached_translation(obj).language_code, 'en')
def test_get_cached_translation(self): obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(0): self.assertIs(get_cached_translation(obj), None) self.assertFalse(obj._meta.get_field('_hvad_query').is_cached(obj)) obj.translate('sr') self.assertIsNot(get_cached_translation(obj), None) self.assertEqual(get_cached_translation(obj).language_code, 'sr') old = set_cached_translation(obj, obj.translations.get_language('ja')) with self.assertNumQueries(0): self.assertEqual(old.language_code, 'sr') self.assertEqual(obj.language_code, 'ja') self.assertEqual(get_cached_translation(obj).language_code, 'ja') set_cached_translation(obj, None) self.assertIs(get_cached_translation(obj), None) self.assertFalse(obj._meta.get_field('_hvad_query').is_cached(obj)) obj = Normal.objects.language('en').get(pk=self.normal_id[1]) with self.assertNumQueries(0): self.assertEqual(get_cached_translation(obj).language_code, 'en')
def safe_translation_getter(self, name, default=None): cache = get_cached_translation(self) if cache is None: return default return getattr(cache, name, default)
def save_translations(cls, instance, **kwargs): 'Signal handler for post_save' translation = get_cached_translation(instance) if translation is not None: translation.master = instance translation.save()
def validate_unique(self, exclude=None): super(TranslatableModel, self).validate_unique(exclude=exclude) translation = get_cached_translation(self) if translation is not None: translation.validate_unique(exclude=exclude)
def __str__(self): return ( "%s, %s <%s>" % (self.name, self.translated_field, self.language_code) if get_cached_translation(self) is not None else "%s <none>" % self.name )
def __str__(self): return ('%s, %s <%s>' % (self.name, self.translated_field, self.language_code) if get_cached_translation(self) is not None else '%s <none>' % self.name)
def get_current_translation(self): """ Get the translation model (hvad) from the current shared model instance """ return get_cached_translation(self)
def clean_fields(self, exclude=None): super(TranslatableModel, self).clean_fields(exclude=exclude) translation = get_cached_translation(self) if translation is not None: translation.clean_fields(exclude=exclude + ['id', 'master', 'master_id', 'language_code'])