【问题标题】:How to merge two querysets django如何合并两个查询集 django
【发布时间】:2019-08-11 14:28:47
【问题描述】:

我正在尝试获取最新 100 个帖子的列表,以及该帖子用户的已批准、待处理和已拒绝帖子的总计数。

models.py

class BlogPost(models.Model):
    POST_STATUSES = (
                    ('A', 'Approved'),
                    ('P', 'Pending'),
                    ('R', 'Rejected')
                    )
    author = models.ForeignKey(User)
    title = models.CharField(max_length=50)
    description = models.TextField()
    status = models.ChoiceField(max_length=1, choices=POST_STATUSES)

views.py

现在我得到这样的汇总计数,但我对如何将计数与帖子标题合并感到困惑

top_post_users = list(BlogPost.objects.values_list('user_id', flat=True))[:100]
users =  User.objects.filter(pk__in=top_post_users).annotate(approved_count=Count(Case(When(user_posts__status="A", then=1),output_field=IntegerField()))).annotate(pending_count=Count(Case(When(user_posts__status="P", then=1),output_field=IntegerField()))).annotate(reject_count=Count(Case(When(user_posts__status="R", then=1),output_field=IntegerField())))
users.values('approved_count', 'pending_count', 'reject_count')

这是我想要的结果:

  • 帖子标题,作者1、10、5、1
  • 文章标题2、作者2、7、3、1
  • 文章标题3、作者1、10、5、1

如何将返回的计数与标题合并?

我知道我可以使用一个 for 循环并附加每个循环,但是从效率上讲,我认为这不是正确的方法。有没有更高效的方式使用django数据库ORM?

我试过了

users.values('title', approved_count', 'pending_count', 'reject_count')

...这行得通,但它返回的帖子超过了最新的 100 个帖子,所以我认为它正在获取这些用户的所有帖子和汇总计数。

【问题讨论】:

  • 这里的 10,5,1 等是什么?
  • 如果您可以将查询集转换为不同的数据结构,例如list,我很确定pandas 有工具可以让这更容易。虽然不确定它们是什么
  • @JPG 已批准计数、待处理计数、已拒绝计数
  • 我想我可以使用pandas..我大致知道如何使用它进行合并,但我想将其保留为数据库查询操作@Green Cloak Guy

标签: python django


【解决方案1】:

最终,您需要一个博客帖子列表:

main_qs = BlogPost.objects
# add filters, ordering etc. of the posts

并且您不仅希望在帖子标题旁边显示作者,还希望通过带注释的计数来丰富作者信息。

from django.db.models import OuterRef, Subquery, Count

# you need subqueries to annotate the blog posts
base_sub_qs = BlogPost.objects.filter(author__pk=OuterRef('author__pk'))

# add subqueries for each count
main_qs = main_qs.annotate(
    user_approved_count=Subquery(base_sub_qs.filter(status="A").annotate(
            c=Count('*')).values('c'), output_field=IntegerField()),
    user_pending_count=Subquery(base_sub_qs.filter(status="P").annotate(
            c=Count('*')).values('c'), output_field=IntegerField()),
    user_rejected_count=Subquery(base_sub_qs.filter(status="R").annotate(
            c=Count('*')).values('c'), output_field=IntegerField()),
)

然后您可以在模板中访问这些:

{% for post in posts %}
    {{ post.title }}
    {{ post.author.get_full_name }}
    approved: {{ post.user_approved_count }}
    pending: {{ post.user_pending_count }}
    rejected: {{ post.user_rejected_count }}
{% endfor %}

文档:https://docs.djangoproject.com/en/2.1/ref/models/expressions/#subquery-expressions

【讨论】:

  • 我收到一个错误:'Query' 对象没有属性'contains_aggregate'
  • 我已经更改了代码。试图将我的工作代码转换为您的用例。我认为您的代码可能允许使用更简单的版本,但您仍然需要 Subquery 才能使 OuterRef 工作。
  • 现在我得到这个:子查询返回超过 1 行
  • values('c') 旨在防止这种情况。请确保您已将其添加到所有子查询中。
  • 是的,这就是我感到困惑的原因,它看起来正确并且在逻辑上是有道理的,但它仍然返回不止一行......
猜你喜欢
  • 2017-12-04
  • 2021-11-10
  • 2010-10-17
  • 2013-09-06
  • 1970-01-01
  • 2017-06-04
  • 2017-03-09
  • 2014-02-23
  • 2011-05-23
相关资源
最近更新 更多