【问题标题】:Add a boolean field if a row exists in another table?如果行存在于另一个表中,添加一个布尔字段?
【发布时间】:2015-06-04 09:56:35
【问题描述】:

我有两个表,分别名为 PostReply。用户只能为每个Post 创建一个Response。模型如下所示:

class Post(models.Model):
    name = models.CharField(max_length = 100)

class Reply(models.Model):
    post = models.ForeignKey(Post, related_name = 'replies')

现在,我有一个返回帖子的视图,如下所示:

class PostList(generics.ListAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = Post.objects.all()
    serializer_class = PostSerializer

还有一个帖子的序列化器:

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        fields = ('id', 'name')

此视图的结果如下所示:

[
    {
        "id": "1",
        "name": "The first post"
    },
    {
        "id": "2",
        "name": "The second post"
    }
]

现在,针对实际问题:如果用户已回复帖子,我想在结果中添加一个布尔字段 true,如果没有回复,则为 false。基本上,当前用户已回复第一个帖子但未回复第二个帖子的情况的结果如下所示:

[
    {
        "id": "1",
        "name": "The first post",
        "replied": "true"
    },
    {
        "id": "2",
        "name": "The second post",
        "replied": "false"
    }
]

我如何实现这一目标?我有一种预感,这应该以某种方式在序列化程序中实现,但我不知道该怎么做。

提前感谢您的帮助!

【问题讨论】:

  • 第一个想法是在您的序列化程序中添加自定义序列化程序方法字段(django-rest-framework.org/api-guide/fields/…),但请记住,您的序列化程序类中必须有当前用户对象(例如,您可以覆盖序列化构造函数来传递它)。

标签: python django django-rest-framework django-1.7


【解决方案1】:

您可以将自定义字段添加到您的PostSerializer

class PostSerializer(serializers.ModelSerializer):
    replied = serializers.SerializerMethodField('has_replies')

    def has_replies(post):
        return post.replies.filter(owner=self.context["request"].user).exists()

    class Meta:
        fields = ('id', 'name', 'replied')

【讨论】:

  • 问题是request.user是否回复了帖子,不是任何用户
  • 我明白了,您可以通过self.context["request"] 访问序列化程序中的request。上下文由ListAPIView.get_serializer_context 方法设置。假设Reply对象有一个叫owner的字段,可以使用上面的答案。
  • 这不会导致has_replies() 中的额外查询在原始查询中每行执行一次吗?
【解决方案2】:

在这里借鉴 dydek 的回答。

您在 Api 视图中覆盖您的 get_queryset

class PostList(generics.ListAPIView):
    ...
    def get_queryset(self):
        Post.objects.all().extra(select={
        'current_user_replies_count': 'SELECT COUNT(*) FROM <reply table> WHERE' +
        'post_id=posts_post.id AND owner_id = %s'
                                  },select_params=(request.user.id,))

这会将“current_user_replies_count”作为属性添加到查询集中的 Post 对象。

【讨论】:

  • 你能解释一下post_id=posts_post.id的关系吗?谢谢
【解决方案3】:

这里的下一个问题是很多 sql 查询,例如当您要获取时。 100 个对象(您将拥有 BASE_QUERIES_COUNT + len(objects) )。当然,我们不希望有线性 sql 查询计数,而这种情况 永远不会发生,尤其是在生产版本中。完美的 这里的解决方案是,如果我们能够获取所有数据 一个sql查询。这可以通过覆盖get_queryset 方法(此处为https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/generics.py#L47)来实现。然后查询集可能如下所示,参数current_user_replies_count 可用作普通模型实例变量。

# all only for example
Post.objects.all().extra(select={
        'current_user_replies_count': 'SELECT COUNT(*) FROM <reply table> WHERE '+
                                      'post_id=posts_post.id AND owner_id = %s'
    },
    select_params=(request.user.id,)
)

我还没有测试过,所以更多地使用它作为示例而不是现成的解决方案, 并且您应该将 current_user_replies_count 转换为 bool。

【讨论】:

  • 我无法理解我应该如何在我的代码中实现这一点。
猜你喜欢
  • 1970-01-01
  • 2021-10-24
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多