Django 查询使用 .order_by() 和 .latest()
我有一个模型:
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 个回答
这个对我有效
latestsetuplist = SetupTemplate.objects.order_by('-creationTime')[:10][::1]
我想这应该是一个在Django中已知的错误,这个问题在1.3版本发布后已经被修复了。
我本以为 .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_by
。LIMIT
是后面加上的,得益于 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