Проблема пагинации и нарезки в 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]

Но я не думаю, что это должно работать таким образом.

Вернуться на верх