4

我想GenericRelation在 DRF中包含一个带有后向参考的模型

文档表明这应该很容易(就在上面: http: //www.django-rest-framework.org/api-guide/relations/#manytomanyfields-with-a-through-model) - 但我错过了一些东西!

请注意,使用 GenericRelation 字段表示的反向通用键可以使用常规关系字段类型进行序列化,因为关系中目标的类型始终是已知的。

有关更多信息,请参阅有关泛型关系的 Django 文档。

我的模型:

class Voteable(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

    direct_vote_count = models.IntegerField(default=0)

class Question(models.Model):
    user = models.ForeignKey(UserExtra, related_name='questions_asked')
    voteable = GenericRelation(Voteable)
    question = models.CharField(max_length=200)

和我的序列化器:

class VoteableSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Voteable
        fields = ('pk', 'id', 'url', 'direct_vote_count')


class QuestionSerializer(serializers.HyperlinkedModelSerializer):
    #voteable = VoteableSerializer(read_only=True, many=False)
    #voteable = serializers.PrimaryKeyRelatedField(many=False, read_only=True)

    class Meta:
        depth = 1
        model = Question
        fields = ('url', 'question', 'user', 'voteable')

被注释掉的两行是我试图告诉 DRF 如何在voteable里面序列化Question
第一行给了我

'GenericRelatedObjectManager' object has no attribute 'pk'

第二个

<django.contrib.contenttypes.fields.create_generic_related_manager.<locals>.GenericRelatedObjectManager object at 0x7f7f3756cf60> is not JSON serializable

所以,显然我误解了一些东西,知道什么吗?

4

3 回答 3

2

好吧,我有一个可行的解决方案,尽管它感觉不是正确的解决方案....

class VoteableSerializer(serializers.ModelSerializer):
    class Meta:
        model = Voteable
        fields = ('pk', 'direct_vote_count')


class VoteableRelatedField(serializers.RelatedField):
    def to_representation(self, value):
        serializer = VoteableSerializer(value.get_queryset()[0])
        return serializer.data

class QuestionSerializer(serializers.HyperlinkedModelSerializer):
    #voteable = VoteableSerializer(read_only=True, many=False)
    #voteable = serializers.PrimaryKeyRelatedField(many=False, read_only=True)

    voteable = VoteableRelatedField(read_only=True)

    class Meta:
        depth = 1
        model = Question
        fields = ('url', 'question', 'user', 'voteable')
        read_only_fields = ('voteable',)
  • url_VoteableSerializer
  • 更改VoteableSerializerModelSerializerHyperlinkedModelSerializer
  • 从查询集中添加VoteableRelatedField并获取第一项(这尤其感觉不对)

我不会将此标记为已接受,希望有人能启发我该如何做!

于 2015-12-30T00:47:53.143 回答
2

解决方案的替代想法,似乎更适合 GenericRelation...

  • 使 Voteable 成为一个抽象模型
  • 使用 GenericForeignKey 更改投票类(此问题中未显示)以指向任何内容。

优点:
这意味着投票信息总是在相关对象上正确,简化排序和查询并避免连接。

缺点:
投票会占用更多空间

class Voteable(models.Model):
    votes = GenericRelation(Vote)
    direct_vote_count = models.IntegerField(default=0)

    class Meta:
        abstract = True

class Question(Voteable):
    user = models.ForeignKey(UserExtra, related_name='questions_asked')
    question = models.CharField(max_length=200)

class Vote(models.Model):
    user = models.ForeignKey(UserExtra, related_name='questions_asked')
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

可能更优化,但更少 DRY 的方法是为继承的每种类型的对象设置一个单独的“投票”类Voteable

class Voteable(models.Model):
    direct_vote_count = models.IntegerField(default=0)

    class Meta:
        abstract = True

class Question(Voteable):
    user = models.ForeignKey(UserExtra, related_name='questions_asked')
    question = models.CharField(max_length=200)

class QuestionVote(models.Model):#This class also repeated for each item that can be voted on
    user = models.ForeignKey(UserExtra, related_name='questions_asked')
    parent = models.ForeignKey(Question, related_name='votes')
于 2015-12-30T02:12:07.603 回答
1

一个自定义相关的序列化器字段似乎是不必要的,因为文档有这个 GenericRelation 的脚注:

请注意,使用 GenericRelation 字段表示的反向通用键可以使用常规关系字段类型进行序列化,因为关系中目标的类型始终是已知的。

申请如下。还要检查这个DRF3 扩展。

class QuestionSerializer(serializers.HyperlinkedModelSerializer):
    voteable = VoteableSerializer(read_only=True)

    class Meta:
        model = Question
        fields = ('url', 'question', 'user', 'voteable')
        ...
于 2017-07-26T13:09:12.270 回答