热门标签:
Q:

Django Rest框架和Django-Hvad

所以我需要为我的DRF API提供一些模型翻译支持,我开始使用django-hvad。

它似乎与我的django应用程序很好地工作,但我在DRF APi中遇到了一些问题。

我试图创建一个简单的POST请求,我得到一个错误:

Accessing a translated field requires that the instance has a translation loaded, or a valid translation in current language (en) loadable from the database

以下是我的模型,序列化器和视图集:

模型:

class Mission(TranslatableModel):
    translations = TranslatedFields(
        mission=models.CharField(max_length=255, help_text="Mission name"),
    )

    def __unicode__(self):
        return self.lazy_translation_getter('mission', str(self.pk))

序列化器:

class MissionSerializer(serializers.ModelSerializer):
    mission = serializers.CharField(source='mission')

    class Meta:
        model = Mission

视图集:

class MissionViewSet(viewsets.ModelViewSet):
    queryset = Mission.objects.language().all()
    serializer_class = MissionSerializer
    authentication_classes = (NoAuthentication,)
    permission_classes = (AllowAny,)

    def get_queryset(self):
        # Set Language For Translations
        user_language = self.request.GET.get('language')
        if user_language:
            translation.activate(user_language)
        return Mission.objects.language().all()

有人知道我怎么能解决这个问题吗?? 我也开放给其他建议的应用程序已知的工作,但我真的很想有这个工作

原网址
A:

我得到了这个工作多亏了这里的Spectrashttps://github.com/KristianOellegaard/django-hvad/issues/211

问题,我猜是DRF试图对模型做一些内省。 我确实在我的一个项目中使用DRF,在一个TranslatableModel上。 它需要一些胶水才能正常工作。 我曾经建议将其添加到hvad中,但我们得出结论,这将过度扩展功能集。 也许有一天另一个模块,但我没有足够的时间来维护hvad和那个。

自从我实现它以来已经有一段时间了,所以这里就是这样:

# hvad compatibility for rest_framework - JHA

class TranslatableModelSerializerOptions(serializers.ModelSerializerOptions):
    def __init__(self, meta):
        super(TranslatableModelSerializerOptions, self).__init__(meta)
        # We need this ugly hack as ModelSerializer hardcodes a read_only_fields check
        self.translated_read_only_fields = getattr(meta, 'translated_read_only_fields', ())
        self.translated_write_only_fields = getattr(meta, 'translated_write_only_fields', ())

class HyperlinkedTranslatableModelSerializerOptions(serializers.HyperlinkedModelSerializerOptions):
    def __init__(self, meta):
        super(HyperlinkedTranslatableModelSerializerOptions, self).__init__(meta)
        # We need this ugly hack as ModelSerializer hardcodes a read_only_fields check
        self.translated_read_only_fields = getattr(meta, 'translated_read_only_fields', ())
        self.translated_write_only_fields = getattr(meta, 'translated_write_only_fields', ())

class TranslatableModelMixin(object):
    def get_default_fields(self):
        fields = super(TranslatableModelMixin, self).get_default_fields()
        fields.update(self._get_translated_fields())
        return fields

    def _get_translated_fields(self):
        ret = OrderedDict()
        trans_model = self.opts.model._meta.translations_model
        opts = trans_model._meta

        forward_rels = [field for field in opts.fields
                        if field.serialize and not field.name in ('id', 'master')]

        for trans_field in forward_rels:
            if trans_field.rel:
                raise RuntimeError()
            field = self.get_field(trans_field)
            if field:
                ret[trans_field.name] = field

        for field_name in self.opts.translated_read_only_fields:
            assert field_name in ret
            ret[field_name].read_only = True

        for field_name in self.opts.translated_write_only_fields:
            assert field_name in ret
            ret[field_name].write_only = True

        return ret

    def restore_object(self, attrs, instance=None):
        new_attrs = attrs.copy()
        lang = attrs['language_code']
        del new_attrs['language_code']

        if instance is None:
            # create an empty instance, pre-translated
            instance = self.opts.model()
            instance.translate(lang)
        else:
            # check we are updating the correct translation
            tcache = self.opts.model._meta.translations_cache
            translation = getattr(instance, tcache, None)
            if not translation or translation.language_code != lang:
                # nope, get the translation we are updating, or create it if needed
                try:
                    translation = instance.translations.get_language(lang)
                except instance.translations.model.DoesNotExist:
                    instance.translate(lang)
                else:
                    setattr(instance, tcache, translation)

        return super(TranslatableModelMixin, self).restore_object(new_attrs, instance)

class TranslatableModelSerializer(TranslatableModelMixin, serializers.ModelSerializer):
    _options_class = TranslatableModelSerializerOptions

class HyperlinkedTranslatableModelSerializer(TranslatableModelMixin,
                                             serializers.HyperlinkedModelSerializer):
    _options_class = HyperlinkedTranslatableModelSerializerOptions

从那里,你只是从TranslatableModelSerializerHyperlinkedTranslatableModelSerializer继承你的序列化器。 发布时,您应该简单地将language_code添加为普通字段,作为JSON/XML/whatever的一部分。

主要技巧是在restore_object方法中。 对象创建需要包括翻译加载。

相似问题