def update(self, instance, data): accessor = self.Meta.model._meta.translations_accessor translations_data = data.pop(accessor, None) if translations_data: arbitrary = translations_data.popitem() data.update(arbitrary[1]) stashed = set_cached_translation( instance, load_translation(instance, arbitrary[0], enforce=True)) instance = super(TranslationsMixin, self).update(instance, data) for language, translation_data in translations_data.items(): set_cached_translation( instance, load_translation(instance, language, enforce=True)) self.update_translation(instance, translation_data) set_cached_translation(instance, stashed) qs = instance._meta.translations_model.objects (qs.filter(master=instance).exclude( language_code__in=(arbitrary[0], ) + tuple(translations_data.keys())).delete()) else: instance = super(TranslationsMixin, self).update(instance, data) return instance
def test_load_translation_normal(self): # no translation loaded, one exists in db for language obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): translation = load_translation(obj, 'en') self.assertIsNot(translation.pk, None) self.assertEqual(translation.language_code, 'en') self.assertEqual(translation.translated_field, NORMAL[1].translated_field['en']) # no translation loaded, none exists for language obj = Normal.objects.untranslated().get(pk=self.normal_id[1]) with self.assertNumQueries(1): translation = load_translation(obj, 'xx') self.assertIsInstance(translation, Normal._meta.translations_model) self.assertIs(translation.pk, None) self.assertEqual(translation.language_code, 'xx') # no translation is loaded, prefetch enabled obj = Normal.objects.untranslated().prefetch_related('translations').get(pk=self.normal_id[1]) with self.assertNumQueries(0): translation = load_translation(obj, 'ja') self.assertIsNot(translation.pk, None) self.assertEqual(translation.language_code, 'ja') self.assertEqual(translation.translated_field, NORMAL[1].translated_field['ja']) # translation loaded, it should be used regardless of language obj = Normal.objects.language('en').get(pk=self.normal_id[1]) with self.assertNumQueries(0): translation = load_translation(obj, 'ja') self.assertIsNot(translation.pk, None) self.assertEqual(translation.language_code, 'en') self.assertEqual(translation.translated_field, NORMAL[1].translated_field['en'])
def test_load_translation_enforce(self): # correct translation loaded, it should be used obj = Normal.objects.language('ja').get(pk=self.normal_id[1]) with self.assertNumQueries(0): translation = load_translation(obj, 'ja', enforce=True) self.assertIsNot(translation.pk, None) self.assertEqual(translation.language_code, 'ja') self.assertEqual(translation.translated_field, NORMAL[1].translated_field['ja']) # wrong translation loaded, it should be reloaded obj = Normal.objects.language('en').get(pk=self.normal_id[1]) with self.assertNumQueries(1): translation = load_translation(obj, 'ja', enforce=True) self.assertIsNot(translation.pk, None) self.assertEqual(translation.language_code, 'ja') self.assertEqual(translation.translated_field, NORMAL[1].translated_field['ja']) # wrong translation loaded, reloading fails, it should be created obj = Normal.objects.language('en').get(pk=self.normal_id[1]) with self.assertNumQueries(1): translation = load_translation(obj, 'sr', enforce=True) self.assertIs(translation.pk, None) self.assertEqual(translation.language_code, 'sr')
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 object_data = {} language = getattr(self, "language", get_language()) if instance is not None: trans = load_translation(instance, language, enforce=True) if trans.pk: 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 object_data.update(initial or {}) super(TranslatableModelForm, self).__init__( data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance )
def save(self, commit=True): ''' Saves the model If will always use the language specified in self.cleaned_data, with the usual None meaning 'call get_language()'. If instance has another language loaded, it gets reloaded with the new language. If no language is specified in self.cleaned_data, assume the instance is preloaded with correct language. ''' assert self.is_valid(), ('Method save() must not be called on an invalid ' 'form. Check the result of .is_valid() before ' 'calling save().') # Get the right translation for object and language # It should have been done in _post_clean, but instance may have been # changed since. enforce = 'language_code' in self.cleaned_data if getattr(self, 'is_edit', False): language = self.language or get_language() else: language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) # Fill the translated fields with values from the form excludes = list(self._meta.exclude) + ['master', 'language_code'] translation = construct_instance(self, translation, self._meta.fields, excludes) if getattr(self, 'is_edit', False): translation.language_code = \ self.cleaned_data.get('language_code', None) or self.new_lang set_cached_translation(self.instance, translation) # Delegate shared fields to super() return super(BaseTranslatableModelForm, self).save(commit=commit)
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, **kwargs): # Insert values of instance's translated fields into 'initial' dict object_data = {} enforce = hasattr(self, 'language') language = getattr(self, 'language', None) or get_language() if instance is not None: translation = load_translation(instance, language, enforce) if translation.pk: exclude = (tuple(self._meta.exclude or ()) + veto_fields) object_data.update( model_to_dict(translation, self._meta.fields, exclude)) if initial is not None: object_data.update(initial) super(BaseTranslatableModelForm, self).__init__(data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance, **kwargs)
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, **kwargs): """ """ opts = self._meta object_data = {} language = getattr(self, 'language', get_language()) if instance is not None: trans = load_translation(instance, language, enforce=True) if trans.pk: 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 object_data.update(initial or {}) super(TranslatableModelForm, self).__init__(data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance, **kwargs)
def save(self, commit=True): ''' Saves the model If will always use the language specified in self.cleaned_data, with the usual None meaning 'call get_language()'. If instance has another language loaded, it gets reloaded with the new language. If no language is specified in self.cleaned_data, assume the instance is preloaded with correct language. ''' assert self.is_valid(), ( 'Method save() must not be called on an invalid ' 'form. Check the result of .is_valid() before ' 'calling save().') # Get the right translation for object and language # It should have been done in _post_clean, but instance may have been # changed since. enforce = 'language_code' in self.cleaned_data language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) # Fill the translated fields with values from the form excludes = list(self._meta.exclude) + ['master', 'language_code'] translation = construct_instance(self, translation, self._meta.fields, excludes) set_cached_translation(self.instance, translation) # Delegate shared fields to super() return super(BaseTranslatableModelForm, self).save(commit=commit)
def update(self, instance, data): 'Handle switching to correct translation before actual update' enforce = 'language_code' in data language = data.pop('language_code', None) or get_language() translation = load_translation(instance, language, enforce) set_cached_translation(instance, translation) return super(TranslatableModelMixin, self).update(instance, data)
def to_representation(self, instance): 'Switch language if we are in enforce mode' enforce = hasattr(self, 'language') language = getattr(self, 'language', None) or get_language() translation = load_translation(instance, language, enforce) set_cached_translation(instance, translation) return super(TranslatableModelMixin, self).to_representation(instance)
def get_translation(self, language_code=get_language()): """ Returns a translation of this instance for the given language_code A valid translation instance is always returned. It will be loaded from the database as required. If this fails, a new, empty, ready-to-use translation will be returned. """ return load_translation(self, language_code, enforce=True)
def update(self, instance, data): accessor = self.Meta.model._meta.translations_accessor translations_data = data.pop(accessor, None) if translations_data: arbitrary = translations_data.popitem() data.update(arbitrary[1]) stashed = set_cached_translation( instance, load_translation(instance, arbitrary[0], enforce=True) ) instance = super(TranslationsMixin, self).update(instance, data) for language, translation_data in translations_data.items(): set_cached_translation(instance, load_translation(instance, language, enforce=True)) self.update_translation(instance, translation_data) set_cached_translation(instance, stashed) qs = instance._meta.translations_model.objects (qs.filter(master=instance) .exclude(language_code__in=(arbitrary[0],)+tuple(translations_data.keys())) .delete()) else: instance = super(TranslationsMixin, self).update(instance, data) return instance
def _post_clean(self): ''' Switch the translation on self.instance This cannot (and should not) be done in clean() because it could be overriden to change the language. Yet it should be done before save() to allow an overriden save to set some translated field values before invoking super(). ''' result = super(BaseTranslatableModelForm, self)._post_clean() enforce = 'language_code' in self.cleaned_data language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) set_cached_translation(self.instance, translation) return result
def _post_clean(self): ''' Switch the translation on self.instance This cannot (and should not) be done in clean() because it could be overriden to change the language. Yet it should be done before save() to allow an overriden save to set some translated field values before invoking super(). ''' enforce = 'language_code' in self.cleaned_data if getattr(self, 'is_edit', False): language = self.language or get_language() result = super(BaseTranslatableModelForm, self)._post_clean() else: language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) exclude = self._get_validation_exclusions() translation = construct_instance(self, translation, self._meta.fields, exclude) set_cached_translation(self.instance, translation) if not getattr(self, 'is_edit', False): result = super(BaseTranslatableModelForm, self)._post_clean() return result
def save(self, commit=True): ''' Saves the model If will always use the language specified in self.cleaned_data, with the usual None meaning 'call get_language()'. If instance has another language loaded, it gets reloaded with the new language. If no language is specified in self.cleaned_data, assume the instance is preloaded with correct language. ''' if not self.is_valid(): # raise in 1.3, remove in 1.5 warnings.warn( 'Calling save() on an invalid form is deprecated and ' 'will fail in the future. Check the result of .is_valid() ' 'before calling save().', DeprecationWarning, stacklevel=2) raise ValueError((_( "The %s could not be created because the data didn't validate." ) if self.instance.pk is None else _( "The %s could not be changed because the data didn't validate." )) % self.instance._meta.object_name) # Get the right translation for object and language # It should have been done in _post_clean, but instance may have been # changed since. enforce = 'language_code' in self.cleaned_data language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) # Fill the translated fields with values from the form excludes = list(self._meta.exclude) + ['master', 'language_code'] translation = construct_instance(self, translation, self._meta.fields, excludes) set_cached_translation(self.instance, translation) # Delegate shared fields to super() return super(BaseTranslatableModelForm, self).save(commit=commit)
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): # Insert values of instance's translated fields into 'initial' dict object_data = {} enforce = hasattr(self, 'language') language = getattr(self, 'language', None) or get_language() if instance is not None: translation = load_translation(instance, language, enforce) if translation.pk: exclude = (tuple(self._meta.exclude or ()) + veto_fields) object_data.update( model_to_dict(translation, self._meta.fields, exclude) ) if initial is not None: object_data.update(initial) super(BaseTranslatableModelForm, self).__init__( data, files, auto_id, prefix, object_data, error_class, label_suffix, empty_permitted, instance )
def save(self, commit=True): ''' Saves the model If will always use the language specified in self.cleaned_data, with the usual None meaning 'call get_language()'. If instance has another language loaded, it gets reloaded with the new language. If no language is specified in self.cleaned_data, assume the instance is preloaded with correct language. ''' if not self.is_valid(): # raise in 1.3, remove in 1.5 warnings.warn('Calling save() on an invalid form is deprecated and ' 'will fail in the future. Check the result of .is_valid() ' 'before calling save().', DeprecationWarning, stacklevel=2) raise ValueError(( _("The %s could not be created because the data didn't validate.") if self.instance.pk is None else _("The %s could not be changed because the data didn't validate.") ) % self.instance._meta.object_name ) # Get the right translation for object and language # It should have been done in _post_clean, but instance may have been # changed since. enforce = 'language_code' in self.cleaned_data language = self.cleaned_data.get('language_code') or get_language() translation = load_translation(self.instance, language, enforce) # Fill the translated fields with values from the form excludes = list(self._meta.exclude) + ['master', 'language_code'] translation = construct_instance(self, translation, self._meta.fields, excludes) set_cached_translation(self.instance, translation) # Delegate shared fields to super() return super(BaseTranslatableModelForm, self).save(commit=commit)