Не работает нарезка классов пользовательских кверисетов Django
Мы используем пользовательский объект (pas1_objects). После выполнения некоторой операции фильтрации мы получаем следующий набор запросов.
all_users_queryset = (
User.pas1_objects.select_related("userlogindetails", "usermeta", "tenant").filter(data_filter)
.exclude(
userrolepermissions__role_id__in=["PG", "PD"], tenant_id__in=tenant_ids
)
.order_by(*sort_array)
)
результатом вышеприведенного запроса является -
<KafkaPushQuerySet [<User: User object (bbc306a1-3a75-4e5e-a9b4-6dce0b31b4b3)>, <User: User object (8830ecc1-944a-43e3-a701-331122a26c2b)>, <User: User object (25255aa5-31f9-45d4-9158-5225fba24cb3)>, <User: User object (4a24f883-210b-43a6-9b57-f51fac624a09)>, <User: User object (b6b044c6-cf9b-46f9-91d9-3a31cd4f6d30)>]>
Нарезка на этом наборе запросов не является последовательной.
(Pdb) all_users_queryset[0:1] # first slice is giving correct output
<KafkaPushQuerySet [<User: User object (bbc306a1-3a75-4e5e-a9b4-6dce0b31b4b3)>]>
(Pdb) all_users_queryset[1:2] # this should return 2nd obj in the query set but it return 1st object
<KafkaPushQuerySet [<User: User object (bbc306a1-3a75-4e5e-a9b4-6dce0b31b4b3)>]>
(Pdb) all_users_queryset[2:3] # this works fine
<KafkaPushQuerySet [<User: User object (25255aa5-31f9-45d4-9158-5225fba24cb3)>]>
(Pdb) all_users_queryset[0:2] # this is returning 1st two objects but in reversed order.
<KafkaPushQuerySet [<User: User object (8830ecc1-944a-43e3-a701-331122a26c2b)>, <User: User object (bbc306a1-3a75-4e5e-a9b4-6dce0b31b4b3)>]>
(Pdb) all_users_queryset[0:3] # this is returning correct objets and in correct order.
<KafkaPushQuerySet [<User: User object (bbc306a1-3a75-4e5e-a9b4-6dce0b31b4b3)>, <User: User object (8830ecc1-944a-43e3-a701-331122a26c2b)>, <User: User object (25255aa5-31f9-45d4-9158-5225fba24cb3)>]>
Что может быть причиной такого несоответствия?
context on this pas1_object - Это в основном пользовательский объект, который создается путем наследования models.Manager. и мы переопределили get_queryset, который возвращает нижеприведенный пользовательский набор запросов -
class KafkaPushQuerySet(models.query.QuerySet):
"""
Overriding queryset function to push to kafka
"""
def delete(self):
self.produce_messages_to_kafka(action="delete")
super(KafkaPushQuerySet, self).delete()
def update(self, **kwargs):
super(KafkaPushQuerySet, self).update(**kwargs)
self.produce_messages_to_kafka(action="update")
Спасибо!!!
Количество наборов оценивается только тогда, когда вы их нарезаете. Другими словами, база данных поражается каждый раз, когда вы выполняете операцию нарезки (см. документацию по Django относительно этого момента).
Тогда возникает вопрос: почему эффект вашего метода order_by не одинаков для каждой оценки? Здесь может быть несколько (неисключающих) объяснений, в зависимости от содержимого вашей таблицы базы данных User и вашей переменной sort_array.
- База данных была обновлена между 2 оценками кверисета,
*sort_arrayсоответствует кортежу, который не является длинным, достаточно точным, чтобы порядок был фиксированным и уникальным. Из документации:
Определенное упорядочивание гарантируется только при упорядочивании по набору полей, которые однозначно идентифицируют каждый объект в результатах. Например, если поле
nameне уникально, упорядочивание по нему не гарантирует, что объекты с одинаковыми именами всегда будут появляться в одном и том же порядке.
Простым решением будет принудительная оценка вашего набора queryset перед выполнением нарезки, вызывая list() на нем:
my_list = list(User.pas1_objects.select_related("userlogindetails", "usermeta", "tenant")
.filter(data_filter)
.exclude(userrolepermissions__role_id__in=["PG", "PD"], tenant_id__in=tenant_ids)
.order_by(*sort_array)
)
# And then you can slice your list without any risk of inconsistency
my_list[0:1]