Django相当于每个用户的最新条目

时间:2010-04-05 10:43:07

标签: django

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

使用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'))

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

谢谢,

5 个答案:

答案 0 :(得分:4)

使用order_bydistinct

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

然后在'user'和'created_at'字段中将性能添加到一起。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分: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 )

所以一个选项是使用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 }
)

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

答案 3 :(得分:0)

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

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

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

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

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

我想找到有类别和类别的书籍。列表中的一个优先级对。最后,queryset条件应如下所示:

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

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

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

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

答案 4 :(得分:-1)

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