Beispiel #1
0
    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
Beispiel #2
0
    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'])
Beispiel #3
0
    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'])
Beispiel #4
0
    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')
Beispiel #5
0
    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
        )
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
    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)
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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)
Beispiel #13
0
    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)
Beispiel #14
0
    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)
Beispiel #15
0
    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
Beispiel #16
0
    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')
Beispiel #17
0
    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
Beispiel #18
0
    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
Beispiel #19
0
    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
Beispiel #20
0
    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)
Beispiel #21
0
    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
        )
Beispiel #22
0
    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)