Skip to content

Commit 52a5029

Browse files
committed
django listview reorder note
1 parent b0cc557 commit 52a5029

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
author: shellbye
3+
comments: true
4+
date: 2016-01-07 11:27:08+00:00
5+
layout: post
6+
slug: django-pagination-note
7+
title: Django Pagination note
8+
categories:
9+
- tech_world
10+
tags:
11+
- Django
12+
---
13+
14+
`ListView`中使用了`paginate_by`之后,
15+
并在`template`中使用了`object_list.first`这样的变量时,
16+
Django抛出了如下错误:
17+
18+
> Cannot reorder a query once a slice has been taken.
19+
20+
[Advanced Django ListView]{:target="_blank"}中,我也提到过同样的问题,
21+
但是两者的原因是不一样的。
22+
上一次的错误是`AssertionError at Cannot filter a query once a slice has been taken`
23+
即一旦分片之后,因为SQL已经执行了所以没法再去`filter`
24+
而这一次的问题是不能再排序(`reorder`),之所以说是再排序,
25+
是因为在分页的时候,Django已经进行了一次[排序]{:target="_blank"},
26+
这次排序中,如果在`model`中没有指定排序的方式(`ordering`),
27+
那么就会默认使用其主键(默认为`id`)。
28+
那么第二次排序发生在哪里呢?发生在调用`object_list.first`时,
29+
[源码]{:target="_blank"}可以发现,first并不是简单的取了当前`queryset`的第一个,
30+
而是又一个判断的过程,判断它是否已经排序,若已经排序,则取第一个,
31+
否则按照主键排序再取第一个,这就是第二次排序发生的地方,
32+
究其原因,是因为我在`model`的定义中没有在`Meta`中指定排序字段,
33+
`ordering`.如果指定了该字段,则可以避免上面的问题。
34+
35+
在找资料的过程中,我发现了一种可以避免第二次排序的方式,
36+
就是不用`object_list.first`这样的形式,而用`object_list.0`
37+
这个就不管顺序了,直接取出目前最前面那个,这样同样也不会出现第二次排序,
38+
也不会报错了。
39+
40+
[Advanced Django ListView]:/blog/tech_world/Django-ListView-advance/
41+
[排序]:https://docs.djangoproject.com/en/1.9/ref/models/querysets/#order-by
42+
[源码]:https://github.com/django/django/blob/master/django/db/models/query.py#L544

0 commit comments

Comments
 (0)