首页 > 解决方案 > Django 3.2 中的分页和切片问题

问题描述

你能解释一下 Queryset 切片在 django 中是如何工作的吗?

因为对我来说它有点奇怪。让我解释一下:我有一个简单的任务是通过 AWS 向学生发送电子邮件。AWS SES 每次呼叫的收件人数量有限。

分页

所以我的第一个想法非常简单——使用 django 内置的 Paginator。

代码

AWS_LIMIT = 45

students_queryset = Students.objects.filter(id__in=received_students).order_by('email')
students_paginated = Paginator(students_queryset, AWS_LIMIT)

print(students_queryset.count())

for page_number in students_paginated.page_range:
    student_page = students_paginated.get_page(page_number)
    print(f"{page_number}: {len(student_page.object_list)}")

输出

150
1:45
2:45
3:0
4:0

我希望看到这样的东西:

150
1:45
2:45
3:45
4:15

我试图找到任何解决方案来解决这个问题。但最后我放弃了,决定使用简单的切片。

切片

代码

AWS_LIMIT = 45

def get_index_range(student_count):
    index = -(-student_count//AWS_LIMIT)
    return range(index)

def get_slice(queryset, index):
    start_index = AWS_LIMIT * index
    end_index = start_index + AWS_LIMIT
    print(f'Slice: {start_index}:{end_index}')
    return queryset[start_index:end_index]

students_queryset = Students.objects.filter(id__in=received_students).order_by('email')

print(students_queryset.count())

for index in get_index_range(students.count()):
    students_slice = get_slice(students_queryset, index)
    print(f"{index+1}: {students_slice.count()}")

输出

但结果是一样的

150
Slice: 0:45
1:45
Slice: 45:90
2:45
Slice: 90:135
3:0
Slice: 135:180
4:0

解决方案

我去了 Django 3.2 文档:

通常,对 QuerySet 进行切片会返回一个新的 QuerySet——它不会评估查询。一个例外是,如果您使用 Python 切片语法的“step”参数。

所以我做了一些调整:

AWS_LIMIT = 45

def get_index_range(student_count):
    index = -(-student_count//AWS_LIMIT)
    return range(index)

def get_slice(queryset, index):
    start_index = AWS_LIMIT * index
    end_index = start_index + AWS_LIMIT
    print(f'Slice: {start_index}:{end_index}')
    return queryset[start_index:end_index]

students_queryset = Students.objects.filter(id__in=received_students).order_by('email')

for index in get_index_range(students.count()):
    students_slice = get_slice(students_queryset, index)
    print(f"Students: {students_queryset.count()}")
    print(f"{index+1}: {students_slice.count()}")

结果:

Slice: 0:45
Students: 150
1:45
Slice: 45:90
Students: 105
2:45
Slice: 90:135
Students: 60
3:0
Slice: 135:180
Students: 60
4:0

所以切片改变了原来的查询集。

我改变了一个功能,一切都开始正常工作:

def get_slice(queryset):
    return queryset[0:AWS_LIMIT]

但我认为这不应该以这种方式工作。

标签: pythondjangopaginationslice

解决方案


推荐阅读