在`order_by`调用之后,Django Paginate中的重复元素

dav*_*ong 11 django pagination django-rest-framework

我正在使用Django 1.7.7.

我想知道是否有人经历过这个.这是我的查询:

events = Event.objects.filter(
    Q(date__gt=my_date) | Q(date__isnull=True)
).filter(type__in=[...]).order_by('date')
Run Code Online (Sandbox Code Playgroud)

当我尝试然后分页

p = Paginator(events, 10)
p.count  # Gives 91

event_ids = []
for i in xrange(1, p.count / 10 + 2):
    event_ids += [i.id for i in p.page(i)]

print len(event_ids)  # Still 91
print len(set(event_ids))  # 75
Run Code Online (Sandbox Code Playgroud)

我注意到,如果我删除了.order_by,我没有任何重复.然后我尝试.order_byEvent.objects.all().order_by('date'),没有重复.

最后,我尝试了这个:

events = Event.objects.filter(
    Q(date__gt=my_date) | Q(date__isnull=True)
).order_by('date')

p = Paginator(events, 10)
events.count()  # Gives 131
p.count  # Gives 131

event_ids = []
for i in xrange(1, p.count / 10 + 2):
    event_ids += [i.id for i in p.page(i)]

len(event_ids)  # Gives 131
len(set(event_ids))  # Gives 118
Run Code Online (Sandbox Code Playgroud)

......并且有重复.谁能解释一下发生了什么?

我挖到了Django源代码(https://github.com/django/django/blob/master/django/core/paginator.py#L46-L55),这似乎与Django如何切片有关object_list.

任何帮助表示赞赏.谢谢.

编辑:distinct()对重复项没有影响.数据库中没有任何重复项,我认为查询不会引入任何重复项([e for e in events.iterator()]不会产生任何重复项).就在Paginator切片的时候.

Edit2:这是一个更完整的例子

In [1]: from django.core.paginator import Paginator

In [2]: from datetime import datetime, timedelta

In [3]: my_date = timezone.now()

In [4]:   1 events = Event.objects.filter(
          2     Q(date__gt=my_date) | Q(date__isnull=True)
          3 ).order_by('date')

In [5]: events.count()
Out[5]: 134

In [6]: p = Paginator(events, 10)

In [7]: p.count
Out[7]: 134

In [8]: event_ids = []

In [9]:   1 for i in xrange(1, p.num_pages + 1):
          2     event_ids += [j.id for j in p.page(i)]

In [10]: len(event_ids)
Out[10]: 134

In [11]: len(set(event_ids))
Out[11]: 115
Run Code Online (Sandbox Code Playgroud)

小智 14

哦,在黑暗中拍摄,但我想我可能知道它是什么.我无法在sqlite中重现它,但使用mysql.我认为mysql尝试对具有相同值的列进行排序,它在切片期间返回相同的结果

分页拼接基本上是一个sql语句 SELECT ... FROM ... WHERE (date > D OR date IS NULL) ORDER BY date ASC LIMIT X OFFSET X

但是当date为null时,我不确定mysql是如何对它进行排序的.因此,当我尝试LIMIT 10和LIMIT 10 OFFSET 10的两个SQL查询时,它返回具有相同行的集合,而LIMIT 20生成一个唯一集合.

您可以尝试将order_by更新为order_by('id','date'),以使其首先按唯一字段排序,并且可以修复它.

  • 看起来同样的事情可能会发生在 postgres 上。我已经更新了 `order_by` 以包含一个 `id`,并且当分页器切片查询集时不再有重复项。非常感谢!但我真的很想了解所有这些是如何工作的。所以澄清一下,这是由于排序与 NULL 和 LIMIT + OFFSET 的组合导致了怪异。我发现这个 SO 响应很有帮助并且有些相关 http://stackoverflow.com/questions/9401314/postgresql-odd-offset-limit-behavior-records-order (我会给你一个赞,但我不满足最低要求,恐怕)。 (2认同)

Yar*_*hol 7

.distinct()在将查询传递给 之前尝试使用它Paginator