如何在Django Rest Framework中使用GenericRelation?

时间:2015-12-29 23:49:35

标签: python django serialization django-rest-framework generic-relations

我想在DRF中包含一个GenericRelation反向的模型

文档表明这应该很简单(就在上面: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

所以,显然我误解了什么,不知道是什么?

3 个答案:

答案 0 :(得分: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
  • VoteableSerializer
  • 更改ModelSerializerHyperlinkedModelSerializer
  • 添加VoteableRelatedField并从查询集中获取第一项(特别是这感觉不对)

我还没有将此标记为已被接受,希望有人可以告诉我应该如何

完成!

答案 1 :(得分: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')

也许更优化,但更少的干将是单独的&#34;投票&#34;继承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')

答案 2 :(得分:1)

doc有一个自定义相关的序列化程序字段似乎是GenericRelation的脚注:

  

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

以下申请。同时检查this DRF3扩展名。

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

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