Django:不同的外键

时间:2011-02-08 16:58:29

标签: django foreign-keys distinct

class Log:
 project = ForeignKey(Project)
 msg = CharField(...)
 date = DateField(...)

我想选择四个最新的日志条目,其中每个日志条目必须具有唯一的项目外键。我在谷歌搜索上尝试了这些解决方案,但它们都没有用,而且django文档对于查找来说并不是很好..

我试过像:

Log.objects.all().distinct('project')[:4]
Log.objects.values('project').distinct()[:4]
Log.objects.values_list('project').distinct('project')[:4]

但这不会返回任何内容或同一项目的Log条目..

任何帮助将不胜感激!

4 个答案:

答案 0 :(得分:14)

查询不能像那样 - 在Django的ORM中或在底层的SQL中。如果要获取唯一ID,则只能查询ID。因此,您需要执行两个查询才能获取实际的日志条目。类似的东西:

id_list = Log.objects.order_by('-date').values_list('project_id').distinct()[:4]
entries = Log.objects.filter(id__in=id_list)

答案 1 :(得分:3)

实际上,您可以在SQL中获取project_ids。假设您希望具有最新日志条目的四个项目的唯一项目ID,则SQL将如下所示:

SELECT project_id, max(log.date) as max_date
FROM logs
GROUP BY project_id
ORDER BY max_date DESC LIMIT 4;

现在,您确实需要所有日志信息。在PostgreSQL 8.4及更高版本中,您可以使用窗口函数,但这不适用于其他版本/数据库,因此我将采用更复杂的方式:

SELECT logs.*
FROM logs JOIN (
    SELECT project_id, max(log.date) as max_date
    FROM logs
    GROUP BY project_id
    ORDER BY max_date DESC LIMIT 4 ) as latest
ON logs.project_id = latest.project_id
   AND logs.date = latest.max_date;

现在,如果你拥有访问窗口函数的权限,它会更整洁(我想无论如何),并且执行起来肯定更快:

SELECT * FROM (
   SELECT logs.field1, logs.field2, logs.field3, logs.date
       rank() over ( partition by project_id 
                     order by "date" DESC ) as dateorder
   FROM logs ) as logsort
WHERE dateorder = 1
ORDER BY logs.date DESC LIMIT 1;

好吧,也许它不容易理解,但请相信我的话,它在大型数据库上运行速度更快。

我不完全确定如何转换为对象语法,或者即使它确实如此。此外,如果您想获得其他项目数据,则需要加入项目表。

答案 2 :(得分:0)

我知道这是一个老帖子,但在Django 2.0中,我认为你可以使用:

Log.objects.values('project').distinct().order_by('project')[:4]

答案 3 :(得分:0)

您需要两个查询集。好消息是它仍然会导致单次访问数据库(尽管涉及子查询)。

latest_ids_per_project = Log.objects.values_list(
    'project').annotate(latest=Max('date')).order_by(
    '-latest').values_list('project')

log_objects = Log.objects.filter(
     id__in=latest_ids_per_project[:4]).order_by('-date')

这看起来有些令人费解,但实际上导致了一个令人惊讶的紧凑查询:

SELECT "log"."id",
       "log"."project_id",
       "log"."msg"
       "log"."date"
FROM "log"
WHERE "log"."id" IN
    (SELECT U0."id"
     FROM "log" U0
     GROUP BY U0."project_id"
     ORDER BY MAX(U0."date") DESC
     LIMIT 4)
ORDER BY "log"."date" DESC