如何在Django查询中获取外键第一次出现的记录?

2 投票
3 回答
4258 浏览
提问于 2025-04-15 13:43

基本上,我有一个表格,里面有很多外键,我想根据“创建时间”字段查询某个特定键的第一次出现。以博客/条目的例子来说,如果条目模型有一个指向博客的外键和一个指向用户的外键,那么我该如何构建一个查询,来选择某个特定用户为不同博客写的第一条条目呢?

class Blog(models.Model):
    ...

class User(models.Model):
    ...

class Entry(models.Model): 
    blog = models.Foreignkey(Blog)
    user = models.Foreignkey(User)

我想我可能错过了一些技巧,来选择一个博客的第一条条目,然后可以通过添加条件进一步筛选到特定用户:

query = Entry.objects.magicquery.filter(user=user)

不过,也许还有其他更有效的方法。谢谢!

3 个回答

-1

现在没法测试这个

Entry.objects.filter(user=user).distinct("blog").order_by("id")
0

这是个老问题,我知道 - @zalew的回答接近正确,但可能会导致以下错误:

编程错误:SELECT DISTINCT ON 表达式必须与初始的 ORDER BY 表达式匹配

要解决这个问题,可以尝试让查询中的 orderingdistinct 部分对齐:

Entry.objects.filter(user=user).distinct("blog").order_by("blog", "created")

另外,如果有多个条目在完全相同的时间被创建(虽然不太可能,但谁知道呢!),你可以通过在 order_by 中加入 id 来增加确定性:

要解决这个问题,可以尝试让查询中的 orderingdistinct 部分对齐:

Entry.objects.filter(user=user).distinct("blog").order_by("blog", "created", "id")
1

query = Entry.objects.filter(user=user).order_by('id')[0]

这段代码的意思是:先根据用户筛选出相关的记录,然后按照ID从小到大排序,最后只取出第一个结果。

我现在没有安装Django,所以不能测试这行代码。如果你想确认一下我的写法有没有问题,可以查看官方文档:

排序方法

限制查询结果

顺便提一下,关于“限制查询结果”的手册部分有个有趣的说明:

如果你想获取单个对象,而不是一个列表(比如说:SELECT foo FROM bar LIMIT 1),可以用简单的索引来代替切片。举个例子,这段代码会返回数据库中按标题字母顺序排列后的第一个Entry:

Entry.objects.order_by('headline')[0]

编辑:好的,这是我目前能想到的最好方法(根据你和我的评论)。这段代码返回的不是Entry对象,而是它们的ID,命名为entry_id

query = Entry.objects.values('blog').filter(user=user).annotate(Count('blog')).annotate(entry_id=Min('id'))

我会继续寻找更好的方法。

撰写回答