【问题标题】:Join with subquery in Django ORM在 Django ORM 中加入子查询
【发布时间】:2014-09-04 12:09:33
【问题描述】:

我想使用 Django 的 ORM 运行过滤器,这样我就可以在每个用户的最新会话中获得一组不同的用户。我设置了表格,以便user 有很多sessions;有一个UserSession 模型,Session 模型有一个user = models.ForeignKey(User)

到目前为止我尝试的是Users.objects.distinct('username').order_by('session__last_accessed'),但我知道这不会起作用,因为 Django 将session.last_accessed 列放入选择中,因此它返回给我,例如,5 个重复的用户名和 5不同的会话,而不是单个最近的会话和用户。

是否可以通过 Django 的 ORM 查询?

编辑:好的,经过一些 SQL 测试后,我发现我要使用的 SQL 是:

select user.username, sub_query.last_accessed from (
  select user_id, max(last_accessed) as last_accessed
  from session
  group by user_id
) sub_query
join user on
user.id = sub_query.user_id
order by sub_query.last_accessed desc
limit 5

我可以通过Session.objects.values('user').annotate(last_accessed=Max('last_accessed'))sub_query。如何使用这个sub_query 来通过 ORM 获取我想要的数据?

编辑 2:具体来说,我想通过只执行一个查询来做到这一点,就像上面的 SQL 一样。当然,我可以在 Python 中查询两次并进行一些处理,但我更愿意在使用 ORM 时访问数据库。

【问题讨论】:

标签: sql django django-orm


【解决方案1】:

如果您使用的是 mysql 后端,以下解决方案可能会很有用:

users_in_session = Session.objects.values_list('user_id', flat=True)
sessions_by_the_user_list = Session.objects \
                            .filter(user__in=set(users_in_session)) \
                            .order_by('last_accessed').distinct()

如果您使用sub_query,那么order_by('last_accessed') 函数应该足以获取有序列表中的数据。尽管据我测试,这些结果似乎不稳定。

更新:

你可以试试:

Session.objects.values('user') \
  .annotate(last_accessed=Max('last_accessed')) \
  .orde‌​r_by('last_accessed').distinct()

【讨论】:

  • 虽然我可以在 Python 中通过执行多个查询来做到这一点,但我只想在编辑 OP 时像我的 SQL 一样执行一个查询,因为您在 @987654326 上调用 list() @,这将调用数据库。是否可以只用一个查询来执行?
  • 不,我的意思是,您的代码不会在第 1 行调用一次数据库,然后在第 3 行调用一次吗?
  • 我不确定,这里users_in_sessionValuesQuerySet。(我不确定它是否是延迟加载。如果它是延迟加载,那么它是一个查询)。我已经从答案中删除了列表(这肯定是在创建多个查询)
  • @JoshuaSmock 你可以这样尝试: Session.objects.values('user').annotate(last_accessed=Max('last_accessed')).order_by('last_accessed').distinct()
  • 我试过这个查询,它似乎工作!如果你用它更新你的答案,我会接受它。
【解决方案2】:

调用 distinct('username') 永远不应返回重复的用户名。您确定您使用的是支持 .dictinct(fields) 的 Django 版本,即 Django 版本晚于 1.4 吗?在 Django 1.4 之前,.distinct(fields) 被 oRM 接受,但实际上并没有执行正确的 DISTINCT ON 查询。

事情没有按预期工作的另一个提示是 .distinct(username).order_by(session__last_accessed) 不是一个有效的查询 - order_by 应该将用户名作为第一个参数,因为 order_by 必须以字段名称为前缀.distinct() 调用。详情请见https://docs.djangoproject.com/en/1.4/ref/models/querysets/#django.db.models.query.QuerySet.distinct

【讨论】:

  • 这不一定有效,因为在 usernamesession.last_accessed 上都调用了 distinct,并且因为 session.last_accessed 是不同的,所以它将全部返回。
  • Users.objects.distinct('username').order_by('session__last_accessed') 在 Django 1.4+ 中根本不起作用。在 1.4 之前的版本中,该查询被解释为 Users.objects.distinct(True).order_by('session__last_accessed')。 .distinct(*fields) 不会为用户名和 session.last_accessed 调用 distinct。
猜你喜欢
  • 2020-05-26
  • 2014-05-19
  • 2022-01-21
  • 2021-11-15
  • 2012-03-28
  • 2020-12-26
  • 2015-10-26
  • 2017-09-18
  • 2021-09-21
相关资源
最近更新 更多