【问题标题】:Django equivalent for latest entry for each user每个用户的最新条目的 Django 等效项
【发布时间】:2011-02-04 09:29:29
【问题描述】:

我很惊讶这个问题没有出现。在网上找不到太多内容。

使用Entry.objects.latest('created_at')我可以恢复所有Entry对象的最新条目,但是如果我想要每个用户的最新条目?这类似于 SQL 最新记录查询。但是我如何使用 ORM 来实现这一点?这是我的方法,我想知道它是否是做我想做的最有效的方法。

首先我执行一个子查询:对象按用户分组,并为每个用户返回 Max(最新)created_by 字段(created_at__max)然后我根据子查询中的结果过滤 Entry 对象并获取所需的对象。

Entry.objects.filter(created_at__in=Entry.objects.values('user').annotate(Max('created_at')).values_list('created_at__max'))

或使用经理:

class UsersLatest(models.Manager):  

    def get_query_set(self):
        return super(UsersLatest,self).get_query_set().filter(created_at__in=self.model.objects.values('user').annotate(Max('created_at')).values_list('created_at__max'))

有没有更有效的方法?可能没有子查询?

谢谢,

保罗

【问题讨论】:

  • 我想在我的模型中添加一个 is_latest 布尔值,当我在 form.save 方法中保存一个新条目时设置它,然后我恢复以前的 is_latest 对象并将其设为 false ---所以每个条目保存有两个步骤。我不知道这是否是最好的方法。有什么建议吗?

标签: django


【解决方案1】:

使用order_bydistinct

Entry.objects.all().order_by('user', 'created_at').distinct('user')

然后为了提​​高性能,在 'user' 和 'created_at' 字段上添加索引。

但我认为真正的生产方式是使用Redis 来缓存和更新一个id 的最新用户条目列表。

【讨论】:

  • 这种方式在 MySQL 中不支持 @omid-raha
【解决方案2】:

QuerySet 的设计取决于您打算使用它的目的。我不确定你为什么要在最后使用 values_list 方法打破 QuerySet 迭代器。我想您有一个用户状态列表,您可以在其中显示基于该条目模型的最后活动时间。为此,您可能想试试这个:

Users.objects.all().annotate(latest_activity=Max('entries__created_at'))

然后在您的模板中轻松遍历您的用户

{% for user in users %}
{{ user.full_name }}
{{ user.latest_activity|date: "m/d/Y" }}
{% endfor %}

【讨论】:

  • 您好,感谢您的建议,不错的方法。 annotate(Max('created_at')) 返回包含 'user' 和 'created_at__max' 数据的字典列表,我使用 values_list('created_at__max') 将数据过滤到列表中以便与 created_at__in= 一起使用
【解决方案3】:

原始 SQL 将是

SELECT entry.id, entry.title, entry.content, entry.user_id, entry.created_at
FROM
    entry
WHERE
    entry.created_at = ( SELECT Max(e2.created_at) from entry as e2 where e2.user_id = entry.user_id )

所以一种选择是使用extra() modifierwhere 参数:

Entry.objects.extra(where='entry.created_at = ( SELECT Max(e2.created_at) from entry as e2 where e2.user_id = entry.user_id )')

当然,您可能必须将entry 更改为数据库中表的实际名称。假设您对 ._meta 感到满意,您可以试试这个:

Entry.objects.extra( where=
    '%(table)s.created_at = ( SELECT Max(e2.created_at) from %(table)s as e2 where e2.user_id = %(table)s.user_id )' % { 'table':Entry._meta.db_table }
)

可能有一种更优雅的方式来获取表的名称。

【讨论】:

  • 感谢您的建议,完全符合我的要求。我使用 ._as_sql() 检查了我的 Django 查询的 sql,它几乎完全一样
【解决方案4】:

我遇到了类似的问题,就是这样解决的:

priorities = obj.books_set.values('category').annotate(priority=Max('priority'))

注意:我将最大优先级注释为优先级,因为我将重用输出作为过滤条件。

这是具有最低优先级的类别列表。然后我这样做:

>>> priorities[0]
{'category': 1, 'priority': 10}

我想在列表中查找类别和优先级对的书籍。最后查询集的条件应该是这样的:

Q(priorities[0]) | Q(priorities[1]) | ...

要在一行中执行此操作,请在 Q.__or__ 上使用 reduce

reduce(Q.__or__, (Q(**x) for x in priorities))

我知道它比原始 SQL 差一点,但更安全。如果您使用此代码,请注释它,因为它很难阅读。

【讨论】:

    【解决方案5】:

    我想不出一个原始的 sql 查询会获取你需要的集合,所以我怀疑是否有可能用这些结果构造一个 QuerySet。

    【讨论】:

      猜你喜欢
      • 2017-09-27
      • 2019-10-11
      • 2017-01-17
      • 2017-02-18
      • 2017-04-11
      • 1970-01-01
      • 2022-06-15
      • 2011-02-27
      • 2020-03-10
      相关资源
      最近更新 更多