我有以下(简化)模型:
class MyModel(models.Model):
TYPE_SOMETHING = 0
TYPE_SOMETHING_ELSE = 1
TYPE_ANOTHER = 2
type = models.SmallIntegerField()
# other model fields
我想执行一个查询,例如:
MyModel.objects.all()
但是,QuerySet必须按照type
属性进行排序,但要按照特定的顺序:
1. TYPE_SOMETHING_ELSE
2. TYPE_SOMETHING
3. TYPE_ANOTHER
这不是升序或降序。
我该怎么做?
我们可以在djangoSortedDict
的帮助下对queryset
进行排序有关SortedDict
的更多信息,请浏览此文档
from django.utils.datastructures import SortedDict
MyModel.objects.extra( select=SortedDict([('type',
'case when type = %d then 2 when type = %d then 1 else 0 end' %
(MyModel.TYPE_SOMETHING_ELSE, MyModel.TYPE_SOMETHING, MyModel.TYPE_ANOTHER))]) )
.order_by('type')
我发布了一个小型第三方,它通过为您生成CASE WHEN ...
SQL语句来帮助解决此问题。
有了这个库,你可以做:
from django_reorder.reorder import reorder
MyModel.objects.order_by(reorder(type=[TYPE_SOMETHING_ELSE, TYPE_SOMETHING, TYPE_ANOTHER]))
您的查询集将按照您想要的方式进行排序。
我认为你可以这样做:
from django.utils.datastructures import SortedDict
MyModel.objects.extra(select=SortedDict([('types',
'case when type = %d then 2 when type = %d then 1 else 0 end' %
(MyModel.TYPE_SOMETHING_ELSE,MyModel.TYPE_SOMETHING))])
).order_by('types')
这背后的sql查询是
SELECT (case when type = 1 then 2 when type = 0 then 1 else 0 end) AS "type", "testapp_mymodel"."id", "testapp_mymodel"."types" FROM "testapp_mymodel" ORDER BY "types" ASC
SortedDict只用于保留选择选项的顺序
您可以将order_by()
方法与Case()
表达式一起使用:
from django.db.models import Case, When, IntegerField
queryset = MyModel.objects.order_by(Case(
When(type=MyModel.TYPE_ANOTHER, then=0),
When(type=MyModel.TYPE_SOMETHING, then=1),
When(type=MyModel.TYPE_SOMETHING_ELSE, then=2),
output_field=IntegerField()))
这将是一个比使用extra()
和原始SQL更好的选择,Django文档建议不要使用原始SQL。
如果我能正确理解你的问题,你想存储一组整数,但要以非标准的顺序从数据库中检索它们。我不确定常量变量到底是如何融入模式的,但我的建议是,应该将变量名单独存储在一个列表中,以便通过它们的索引访问,从而将变量名排除在外。例如:
choices_list = [TYPE_SOMETHING, TYPE_SOMETHING_ELSE, TYPE_ANOTHER]
TYPE_CHOICES = (
(0, 1),
(1, 0),
(2, 3)
)
class MyModel(models.Model):
type = models.SmallIntegerField(choices=TYPE_CHOICES)
def get_type_display(self):
return choices_list[self.type.id]
如果您想更进一步,可以覆盖SmallIntegerField
以自动返回这些值。
由于Django的SortedDict
已被弃用,我使用了与Annop和Savad KP:类似的答案
import collections
MyModel.objects.extra(
select=collections.SortedDict([(
'types',
'CASE WHEN type = %d THEN 0 ',
'WHEN type = %d THEN 1',
'WHEN type = %s THEN 2',
'END' % (
MyModel.TYPE_ANOTHER,
MyModel.TYPE_SOMETHING,
MyModel.TYPE_SOMETHING_ELSE
))
])
).order_by('types')
最后很简单:)