如何测试Django QuerySets是否按PK升序排列
class Foo(models.Model):
name = models.CharField(max_length=10)
class Meta(object):
ordering = ('pk', )
我想测试一下这个排序是否按照我预期的方式工作。
def test_respect_ordering(self):
Foo.objects.create(name="bar", pk=2)
Foo.objects.create(name="baz", pk=1)
results = Foo.objects.all()
self.assertEqual("baz", results[0].name)
self.assertEqual("bar", results[1].name)
虽然这个排序确实如我所愿,但我的测试无论Meta类或其中定义的排序属性是什么,结果都是通过的。有没有什么方法可以测试这段代码是否真的重要呢?
我为什么想测试这个?我的测试是在SQLite上运行的,但生产环境是用mysql。希望有一天,我们能使用更好的关系数据库管理系统(RDBMS),也许在这些数据库中,结果不会总是按主键返回。
Django文档指出,排序并不是自动进行的。
2 个回答
1
这是一个很老的问题。不过对于未来看到这个问题的人,我建议的方法虽然简单,但实际上可以测试Django模型中查询集的排序。
models.py
class Foo(models.Model):
name = models.CharField(max_length=10)
class Meta(object):
ordering = ('name')
test_models.py
- 这里的测试是用pytest写的,但这个逻辑也可以用unittest模块来实现。
import pyest
from myapp.models import Foo
@pytest.fixture
def foo_1():
return Foo.objects.create(name="ZZZZ")
@pytest.fixture
def foo_2():
return Foo.objects.create(name="AAAA")
@pytest.mark.django_db
def test_foo_ordering(foo_1, foo_2):
foos = Foo.objects.all()
# this checks that the name attribute second item in the queryset
# should be greater than first item name attribute in the queryset.
assert foos[0].name < foos[1].name
这个思路可以扩展到测试Django模型中用于排序的其他属性。
1
如果你在你的 Meta
类里不写 ordering
属性,生成的 SQL 查询就不会有 ORDER BY
这个部分(在 1.4 版本中是这样的)。这就意味着你不能指望结果的行会按照某种特定的顺序排列。
没有特定顺序的 SQL 查询结果通常看起来会有点道理。这是因为查询计划很可能会使用索引来加快查询速度,而索引在没有特定顺序的查询中会对行的顺序产生很大影响。通过 Django 模型生成的表,默认情况下只会在主键上有索引,除非你另有说明。所以一般来说,'无序' 的结果顺序会和按主键排序的顺序非常相似。
不过,这里完全没有保证,这种顺序是不能被依赖的。查询计划在很大程度上取决于数据库引擎,甚至对于同一个引擎上非常相似的查询,结果的顺序也可能会有很大变化。
如果你想要特定的顺序,最好明确指定你想要的顺序。这是确保结果顺序的唯一可靠方法。