Django模型查询集使用.extra()或union在PositiveIntegerField上应用自定义排序

时间:2013-01-14 16:32:48

标签: django django-models django-queryset

对于项目库,用户可以手动对某些项目进行排序,以使它们首先出现。

为此,模型的“排序”不是空的PositiveIntegerField(默认为0)。排序字段大于零的项目是手动排序的,必须出现在排序值为0的未排序项目之前。

可以使用的SQL查询可能是这样的:

(select photo, sort, 0 as priority from photos where sort > 0)
union all
(select photo, sort, 1 as priority from photos where sort = 0)
order by priority, sort

结果如下:

+---------+------+----------+
| photo   | sort | priority |
+---------+------+----------+
| photo-a | 1    | 0        |
| photo-b | 2    | 0        |
| photo-c | 0    | 1        |
| photo-d | 0    | 1        |
| photo-e | 0    | 1        |
| ...                       |

但我无法弄清楚如何使用Django Queryset正确完成它?

我能够将两个不同的查询集与list(chain(q1, q2))合并,但是执行查询,这对于大型集合来说效率很低,特别是如果我的查询集应该传递给通常会应用LIMIT的django.core.paginator分页的OFFSET子句。当然,我可以对每个查询q1q2应用切片,但这有点难看,因为它与分页器的重叠。

也许我试图以错误的方式去做。或者也许应该使用extra()方法完成?

2 个答案:

答案 0 :(得分:1)

执行查询集的联合/合并不是解决方案。更简单的解决方案是在订单声明中使用比较。 stackeoverflow上的answer向我指出了这个简洁的解决方案。

select * from photos order by sort=0, sort

0 = 0被评估为True,等于1,1 = 0是False,等于0等等吗?

转换为Django Queryset:

Photos.objects.extra(select={'sortiszero': 'sort = 0'}, order_by=['sortiszero', 'sort'])

结果:

+---------+------+
| photo   | sort |
+---------+------+
| photo-a | 1    |
| photo-b | 2    |
| photo-c | 0    |
| photo-d | 0    |
| photo-e | 0    |
| ...            |

瞧!

答案 1 :(得分:0)

你应该提供更多细节。

如果你想结合这两套,你可以简单地添加列表:

list1 = SomeModel.objects.filter(sort != 0).order_by('column_name_1','column_name_2')
list2 = SomeModel.objects.filter(sort = 0).order_by('priority','foo')
return list = list1 + list2

或者如果你想使用extra()方法,这里有一个问题:

list = SomeModel.objects.fooMethod().extra(order_by=[foo,])