Проблема пагинации и нарезки в Django 3.2
Можете ли вы объяснить, как работает нарезка кверисетов в django?
Потому что для меня это работает довольно странно. Позвольте мне объяснить: У меня есть простая задача - отправить электронную почту студентам через AWS. AWS SES имеет ограниченное количество получателей на один звонок.
Пагинация
Итак, моя первая идея была довольно проста - использовать встроенный в django Paginator.
Code
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
Я пытался найти какие-либо решения для решения этой проблемы. Но в конце концов я сдался и решил использовать простое нарезание.
Нарезка
Code
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 - она не оценивает запрос. Исключением является использование параметра "step" в синтаксисе Python slice.
Так что я сделал несколько твиков:
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
Так нарезка изменила исходный набор запросов.
Я изменил один func и все стало работать правильно:
def get_slice(queryset):
return queryset[0:AWS_LIMIT]
Но я не думаю, что это должно работать таким образом.