Django筛选调用返回的列表的默认顺序是什么?
简短问题
在连接到PostgreSQL数据库时,从Django的过滤器调用返回的列表默认顺序是什么?
背景
我承认,我在应用层面上做了一个错误的假设,认为返回的列表顺序是固定的,也就是说不使用'order_by'。我查询的项目列表并不是按字母顺序或其他特定顺序排列的。我原以为它会保持与添加到数据库时相同的顺序。
这个假设在数百次查询中都成立,但当顺序在不知情的情况下发生变化时,我的应用程序报告了故障。据我所知,这段时间内没有人更改这些记录,因为我就是唯一维护数据库的人。更让人困惑的是,当在Mac OS X上运行Django应用时,它仍然按预期工作,但在Win XP上,顺序却发生了变化。(注意,提到的数百次查询是在Win XP上进行的。)
如果能对此提供一些见解就太好了,因为我在Django或PostgreSQL的文档中找不到解释操作系统之间差异的内容。
示例调用
required_tests = Card_Test.objects.using(get_database()).filter(name__icontains=key)
编辑
今天和一些同事交流后,我得出了与Björn Lindqvist相同的结论。
回想起来,我确实理解为什么这个错误这么常见。使用ORM(像Django、sqlalchemy等)的一个好处是,你可以在不需要详细了解连接的数据库的情况下编写命令。老实说,我就是这样的用户之一。然而,另一方面,如果不详细了解数据库,调试这样的错误就会非常麻烦,甚至可能导致严重后果。
2 个回答
如果你想让它们按照插入的顺序返回:
在你的模型中添加以下内容:
created = models.DateTimeField(auto_now_add=True, db_index=True)
# last_modified = models.DateTimeField(auto_now=True, db_index=True)
class Meta:
ordering = ['created',]
# ordering = ['-last_modified'] # sort last modified first
这里要强调的是没有默认顺序,这个观点非常重要,因为很多人都搞错了。
数据库中的表和普通的HTML表格不一样,它其实是一个无序的元组集合。很多只用过MySQL的程序员对此感到惊讶,因为在MySQL中,行的顺序往往是可以预测的,这是因为它没有利用一些高级的优化技术。举个例子,在以下查询中,你无法知道会返回哪些行,或者它们的顺序:
select * from table limit 10
select * from table limit 10 offset 10
select * from table order by x limit 10
在最后一个查询中,只有当x列的所有值都是唯一的时候,顺序才是可以预测的。关系型数据库管理系统(RDBMS)可以随意以任何顺序返回行,只要满足选择语句的条件。
虽然你可以在Django层面上添加一个默认的排序,这样会让它在每个没有排序的查询中都加上一个排序的条件:
class Table(models.Model):
...
class Meta:
ordering = ['name']
需要注意的是,如果你并不需要有序的行,这样做可能会影响性能。