Beispiel #1
0
    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')
Beispiel #2
0
    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')
Beispiel #4
0
    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__)
Beispiel #6
0
    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__)
Beispiel #8
0
    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__)
Beispiel #9
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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')
Beispiel #13
0
 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)
Beispiel #15
0
    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
Beispiel #16
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
        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)
Beispiel #17
0
    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')
Beispiel #18
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
     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
     )
Beispiel #19
0
    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
Beispiel #20
0
    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)
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):
     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)
Beispiel #22
0
 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
Beispiel #23
0
 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
Beispiel #24
0
 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
Beispiel #25
0
 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
Beispiel #26
0
    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')
Beispiel #27
0
 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
Beispiel #28
0
 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')
Beispiel #29
0
    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)
Beispiel #30
0
    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
Beispiel #31
0
 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
Beispiel #32
0
 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
Beispiel #33
0
    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
Beispiel #34
0
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
Beispiel #35
0
    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')
Beispiel #36
0
    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')
Beispiel #37
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
        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)
Beispiel #38
0
    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)
Beispiel #39
0
    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')
Beispiel #40
0
    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')
Beispiel #41
0
 def safe_translation_getter(self, name, default=None):
     cache = get_cached_translation(self)
     if cache is None:
         return default
     return getattr(cache, name, default)
Beispiel #42
0
 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()
Beispiel #43
0
 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
     )
Beispiel #45
0
 def safe_translation_getter(self, name, default=None):
     cache = get_cached_translation(self)
     if cache is None:
         return default
     return getattr(cache, name, default)
Beispiel #46
0
 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()
Beispiel #47
0
 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)
Beispiel #48
0
 def get_current_translation(self):
     """
     Get the translation model (hvad) from the current shared
     model instance
     """
     return get_cached_translation(self)
Beispiel #49
0
 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'])
Beispiel #50
0
 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)
Beispiel #51
0
 def get_current_translation(self):
     """
     Get the translation model (hvad) from the current shared
     model instance
     """
     return get_cached_translation(self)