Django 查询使用 .order_by() 和 .latest()

43 投票
4 回答
86507 浏览
提问于 2025-04-16 04:17

我有一个模型:

class MyModel(models.Model):
   creation_date = models.DateTimeField(auto_now_add = True, editable=False)

   class Meta:
      get_latest_by = 'creation_date'

在我的视图中,我有一个查询,它做了以下事情:

instances = MyModel.objects.all().order_by('creation_date')

后来我想用 instances.latest() 来获取最新的实例,但它给我的却是第一个实例。只有当我把排序条件设置为 -creation_date,或者直接把排序条件从查询中去掉时,.latest() 才能给我正确的实例。即使我在用 python manage.py shell 手动测试时也是这样,而不是在视图中。

所以现在我在模型的 Meta 中列出了 order_by = ['creation_date'],而在查询中没有使用这个排序条件,这样就能正常工作了。

我本来以为 .latest() 应该总是根据日期时间字段返回最新的实例。有没有人能告诉我,当你在查询中使用 order_by 时,.latest() 的行为是不是有点奇怪?

4 个回答

0

这个对我有效

latestsetuplist = SetupTemplate.objects.order_by('-creationTime')[:10][::1]
9

我想这应该是一个在Django中已知的错误,这个问题在1.3版本发布后已经被修复了。

76

我本以为 .latest() 方法总是会根据日期和时间字段返回最新的实例。

文档中提到:

如果你的模型的 Meta 指定了 get_latest_by,你可以在调用 latest() 时省略 field_name 参数。Django 会默认使用 get_latest_by 中指定的字段。

这意味着,当你调用 MyModel.objects.latest() 时,你会得到基于日期/时间字段的最新实例。而当我用示例数据测试你的代码时,确实得到了最新的实例。

但后来我想用 instances.latest(),结果却没有给我正确的实例,实际上给了我第一个实例。

你误解了 latest() 的工作方式。当在 MyModel.objects 上调用时,它会返回 中的最新实例。而当在 queryset 上调用 latest 时,它会返回 queryset 中的第一个对象。你的 queryset 包含了所有的 MyModel 实例,并按 creation_date 升序排列。因此,latest 在这个 queryset 上返回 queryset 的第一个行是很自然的。这恰好是 中最旧的行。

要更好地理解,可以查看 latest 执行的查询。

案例 1:

from django.db import connection
MyModel.objects.latest()
print connection.queries[-1]['sql']

这将打印:

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM 
"app_mymodel" ORDER BY "app_mymodel"."creation_date" DESC LIMIT 1

注意按 creation_date DESC 排序和 LIMIT 子句。前者是因为 get_latest_by,而后者是 latest 的贡献。

现在,案例 2:

MyModel.objects.order_by('creation_date').latest()
print connection.queries[-1]['sql']

打印结果为:

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM 
"app_mymodel" ORDER BY "app_mymodel"."creation_date" ASC LIMIT 1

注意排序变成了 creation_date ASC。这是因为显式使用了 order_byLIMIT 是后面加上的,得益于 latest

我们再看看案例 3:在 objects.latest() 中显式指定 field_name

MyModel.objects.latest('id')
print connection.queries[-1]['sql']

显示:

SELECT "app_mymodel"."id", "app_mymodel"."creation_date" FROM "app_mymodel"
ORDER BY "app_mymodel"."id" DESC LIMIT 1

撰写回答