Django REST API 中使用 generic_relations 的 ValidationError 及可写外键访问问题

1 投票
1 回答
820 浏览
提问于 2025-04-18 14:51

我正在使用Django REST API,并且结合generic_relations模块,创建一种类似于Django评论的功能,但不是通过模板,而是通过REST API的功能来实现。

我有一个模型类叫做Annotation,结构大致如下:

class Annotation(BaseCommentAbstractModel):

    paragraph_id = models.PositiveIntegerField(null=False)

    body = models.TextField()
    '''
    Annotations can be written only by logged in users. It is to prevent hit and run comments by people under anonymity.
    '''
    user = models.ForeignKey(DjangoUser, null=False, verbose_name=_('user'), related_name = "annotations")

现在,还有另一个模型,用于内容,这个内容可以是任何东西。比如说,它是一个简单的帖子应用:

class BlogContent(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    body = models.TextField()
    ...
    annotation = GenericRelation(Annotation, content_type_field='content_type', object_id_field='object_pk')

对应的序列化器看起来是这样的:

from generic_relations.relations import GenericRelatedField 

class BlogContentSerializer(serializers.ModelSerializer):
    author_id = serializers.Field(source='author_id.username')
    annotation = serializers.RelatedField(many=True)

    class Meta:
        model = BlogContent
        fields = ('title','created','author_id',
              'data','published_flag', 'url_path','slug','annotation')

class AnnotationSerializer(serializers.ModelSerializer):
    user = serializers.Field(source='user.username')
    content_object = GenericRelatedField({
        BlogContent: serializers.HyperlinkedRelatedField(view_name='annotation:blogcontent-detail'),
        }, read_only=False)

    class Meta:
        model = Annotation
        fields = ('paragraph_id', 'body', 'user', 'content_object')


class UserSerializer(serializers.ModelSerializer):
    blogcontent= serializers.PrimaryKeyRelatedField(many=True) 
    annotations = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = User
        fields = ('username', 'id', 'blogcontent', 'annotations')

现在,问题出在这一行: content_object = GenericRelatedField({ BlogContent: serializers.HyperlinkedRelatedField(view_name='annotation:blogcontent-detail'), }, read_only=False)

如果将通用关系设置为只读,也就是设置read_only=True,那么REST API的浏览功能是正常的。但一旦我把它改成False,服务器就会返回一个验证错误(ValidationError)。

ValidationError at /en/annotation/
[u'Invalid model - model not available.']

查看日志和代码后,似乎在rest_framework.renderers.py中的get_raw_data_form(self, view, method, request)方法里,调用obj = getattr(view, 'object', None)时找不到对象。

这又导致在评估field_to_native函数时,serializer = self.determine_deserializer_for_data(value)generic_relations中,传入的value为空,因此代码就出错了。

有没有其他人遇到过这样的错误,或者能帮我解决这个问题吗?请帮帮我!

错误追踪信息如下:

/home/craft/pirateenv/lib/python2.7/site-packages/django/core/handlers/base.py in get_response
            response = response.render() ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/django/template/response.py in render
        self.content = self.rendered_content ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/response.py in rendered_content
    ret = renderer.render(self.data, media_type, context) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/renderers.py in render
    context = self.get_context(data, accepted_media_type, renderer_context) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/renderers.py in get_context
    raw_data_post_form = self.get_raw_data_form(view, 'POST', request) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/renderers.py in get_raw_data_form
            content = renderer.render(serializer.data, accepted, context) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/serializers.py in data
            self._data = self.to_native(obj) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/rest_framework/serializers.py in to_native
        value = field.field_to_native(obj, field_name) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/generic_relations/relations.py in field_to_native
    serializer = self.determine_deserializer_for_data(value) ...
▶ Local vars
/home/craft/pirateenv/lib/python2.7/site-packages/generic_relations/relations.py in determine_deserializer_for_data
        raise ValidationError(self.error_messages['no_model_match']) ...
▶ Local vars

1 个回答

0

这个问题在这个仓库上也提到过,虽然是在不同的情况下,但提供的解决办法对我也有效,直到作者发布修复版本为止。

解决办法是在调用super方法后加一个if value:的判断。

撰写回答