如何在Django中查询每个用户的最新条目?

问题描述 投票:0回答:5

使用

Entry.objects.latest('created_at')
我可以恢复所有Entry对象的最新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'))

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

django django-queryset django-orm django-filter
5个回答
10
投票

使用order_bydistinct

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

然后为了性能,在“user”和“created_at”字段上添加索引。

但我认为真正的生产方式是使用

Redis
来缓存和更新用户最新条目的id列表。


2
投票

查询集的设计取决于您计划使用它的用途。我不知道为什么你要在最后使用 value_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 %}

1
投票

原始 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 )

因此,一种选择是使用

where 修饰符的 
extra()
参数
:

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 }
)

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


0
投票

我遇到了类似的问题并这样做了:

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

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

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

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

我想查找列表中具有类别和优先级对的书籍。最后查询集条件应该如下所示:

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

要在一行中执行此操作,请在

reduce
上使用
Q.__or__

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

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


-1
投票

我无法想出一个原始的 sql 查询来获取您需要的集合,所以我怀疑是否可以用这些结果构造一个 QuerySet。

© www.soinside.com 2019 - 2024. All rights reserved.