所以我需要为我的 DRF API 提供一些模型翻译支持,我开始使用 django-hvad。
它似乎适用于我的 Django 应用程序,但我在使用 DRF APi 时遇到了一些问题。
我正在尝试创建一个简单的 POST 请求,但出现错误:
访问翻译的字段需要实例加载翻译,或者可以从数据库加载当前语言 (en) 的有效翻译
这是我的模型、序列化器和 View 集:
型号:
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
View 集:
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()
有谁知道我该如何解决这个问题??我也对其他已知可用的推荐应用程序持开放态度,但我真的很想让这个应用程序运行
请您参考如下方法:
多亏了这里的 Spectras https://github.com/KristianOellegaard/django-hvad/issues/211,我才让它工作
我猜这个问题是 DRF 试图对模型进行一些内省(introspection)。我确实在我的一个项目中使用 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
从那里,您只需从 TranslatableModelSerializer 或 HyperlinkedTranslatableModelSerializer 继承序列化程序。发布时,您应该简单地将 language_code 添加为普通字段作为 JSON/XML/其他内容的一部分。
主要技巧在于 restore_object 方法。对象创建需要包括翻译加载。
