使用与django-rest-framework的序列化程序的反向关系

时间:2016-07-01 07:20:58

标签: django django-rest-framework

我的模型看起来像这样:

class User(TimestampedModel):
    name = models.CharField(max_length=30, null=False, blank=False)
    device = models.CharField(max_length=255, null=False, blank=False)


class Comment(TimestampedModel):
    user = models.ForeignKey(User, on_delete=models.PROTECT, blank=True, null=True)
    contents = models.CharField(max_length=510)
    rating = models.IntegerField(blank=False, null=False)

我的序列化器看起来像这样:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('name',)


class CommentListItemSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = Comment
        fields = ('user', 'contents', 'rating')

观点:

class CommentsList(generics.ListAPIView):
    serializer_class = CommentListItemSerializer
    queryset = Comment.objects.all()

它几乎完成了工作;)。我得到的回答如下:

"results": [
    {
        "user": {
            "name": "Ania"
        },
        "contents": "Very good",
        "rating": 6
    },
    {
        "user": {
            "name": "Anuk"
        },
        "contents": "Not very good",
        "rating": 1
    }
]

该回复有两个问题。

  1. 我不想拥有这个嵌套对象" user.name"。我希望将其作为简单的字符串字段接收,例如"username"
  2. Serializer为每个用户进行数据库查询(不是连接,但是单独的查询),以获取他/她的名字。由于那是不可接受的,如何解决这个问题?

2 个答案:

答案 0 :(得分:6)

  

Serializer进行数据库查询(不是连接,而是单独的查询)   为每个用户,获取他/她的名字。

您可以在视图的queryset 属性上使用select_related()。然后访问user.name将不会导致进一步的数据库查询。

class CommentsList(generics.ListAPIView):
    serializer_class = CommentListItemSerializer
    queryset = Comment.objects.all().select_related('user') # use select_related
  

我不想拥有这个嵌套对象"user.name"。我想   将其作为简单字符串字段接收,例如"username"

您可以使用username 参数在序列化程序中定义只读source字段。这将返回username字段作为响应。

class CommentListItemSerializer(serializers.ModelSerializer):
    # define read-only username field
    username = serializers.CharField(source='user.name', read_only=True) 

    class Meta:
        model = Comment
        fields = ('username', 'contents', 'rating')

答案 1 :(得分:2)

您可以将自定义函数添加为字段

class Comment(models.Model):
    user = models.ForeignKey(User, on_delete=models.PROTECT, blank=True, null=True)
    contents = models.CharField(max_length=510)
    rating = models.IntegerField(blank=False, null=False)

    def username(self):
        return self.user.name


class CommentListItemSerializer(serializers.ModelSerializer):

    class Meta:
        model = Comment
        fields = ('username', 'contents', 'rating')