Django Rest框架和Django-Hvad [英] Django Rest Framework and Django-Hvad

查看:166
本文介绍了Django Rest框架和Django-Hvad的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这似乎对我的django应用程序很好我在DRF APi中遇到一些问题。



我正在尝试创建一个简单的POST请求,我收到一个错误:



访问一个已翻译的字段要求该实例具有翻译加载,或以当前语言(en)从数据库加载的有效翻译



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



型号:

  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))

Serializer:

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

class Meta:
model = Mission
pre>

Viewset:

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

def get_queryset(self):
#设置语言为翻译
user_language = self.request.GET.get('language')
如果user_language:
translation.activate( user_language)
return Mission.objects.language()。all()

有没有人知道我怎么可以绕过这个?我也开放给其他建议的应用程序已知工作,但我真的很想有一个这样的工作

解决方案

我得到了工作感谢这里的光谱 https://github.com/KristianOellegaard/django-hvad/issues / 211



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



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

 #hvad兼容性rest_framework  -  JHA 

class TranslatableModelSerializerOptions(serializers.ModelSerializerOptions):
def __init __(self,meta):
super(TranslatableModelSerializerOptions,self).__ init __(meta)
#我们需要这个丑陋的hack作为ModelSerializer hardcodes一个read_only_fields检查
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)
#我们n eed这个丑陋的hack作为ModelSerializer硬编码一个read_only_fields检查
self.translated_read_only_fields = getattr(meta,'converted_read_only_fields',())
self.translated_write_only_fields = getattr(meta,'translations_write_only_fields',())

class TranslatableModelMixin(object):
def get_default_fields(self):
fields = super(TranslatableModelMixin,self).get_default_fields()
fields.update(self._get_translated_fields )
返回字段

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

forward_rels = [opts.fields中的字段字段
如果field.serialize而不是field.name('id','master')] $ b $对于forward_rels,trans_field的b

如果trans_field.rel:
raise Runti meError()
field = self.get_field(trans_field)
if field:
ret [trans_field.name] = field

for field_name in self.opts.translated_read_only_fields :
as ret中的field_name
ret [field_name] .read_only = True

在self.opts.translated_write_only_fields中的field_name:
assert中的field_name
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']

如果实例为无:
#创建一个空实例,预翻译
instance = self.opts.model()
instance.translate(lang)
else:
#检查我们正在更新正确的翻译
tcache = self.opts.model._meta.translations_cache
翻译= getattr(实例,tcache,无)
如果没有翻译或翻译.language_code!= lang:
#nope,得到翻译我们正在更新,或创建它,如果需要
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.HyperlinkedMo delSerializer):
_options_class = HyperlinkedTranslatableModelSerializerOptions

从那里,你只是从 TranslatableModelSerializer HyperlinkedTranslatableModelSerializer 。在POST时,您应该简单地将language_code作为正常字段添加为JSON / XML /的一部分。



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


so i needed to had some model-translation support for my DRF API and i started using django-hvad.

It seems to work well with my django application but i am getting some issues with the DRF APi.

I am trying to create a simple POST request and i am getting a error:

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

Here are my models, serializers and viewsets:

Model:

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))

Serializer:

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

    class Meta:
        model = Mission

Viewset:

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()

Does anyone know how i can get around this?? I am also opened to other suggested apps known to work but i would really like to have this one working

解决方案

I got this to work thanks to the Spectras here https://github.com/KristianOellegaard/django-hvad/issues/211

The issue, I guess is DRF tries to do some introspection on the model. I do use DRF in a project of mine, on a TranslatableModel. It needs some glue to work properly. I once suggested adding that to hvad, but we concluded that that would be overextending the feature set. Maybe another module some day, but I don't have enough time to maintain both hvad and that.

It's been some time since I implemented it, so here it is as is:

# 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

From there, you just inherit your serializers from TranslatableModelSerializer or HyperlinkedTranslatableModelSerializer. When POSTing, you should simple add language_code as a normal field as part of your JSON / XML / whatever.

The main trick is in the restore_object method. Object creation needs to include translation loading.

这篇关于Django Rest框架和Django-Hvad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆