Порядок фильтров влияет на результат запроса в Djongo

Я использую пакет Djongo для подключения к MongoDB из моего приложения Django. Однако в результатах запроса наблюдается несогласованность, хотя этого и не ожидалось.

Вот моя модель:

class Item(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField()
    date = models.DateTimeField(db_index=True)
    port_inventory_id = models.IntegerField(db_index=True)

Этот запрос сначала фильтрует по port_inventory_id, затем по date__range и возвращает правильный результат Код:

items = Item.objects.filter(port_inventory_id=999999).filter(date__range=(date_from, date_to))

Запрос:

SELECT "myapp_item"."id", "myapp_item"."name", "myapp_item"."description", "myapp_item"."date", "myapp_item"."port_inventory_id" FROM "myapp_item" WHERE ("myapp_item"."port_inventory_id" = 999999 AND "myapp_item"."date" BETWEEN 2024-07-12 10:11:23.168955 AND 2024-08-01 10:11:23.168965)

Однако этот запрос сначала фильтрует по date__range, затем по port_inventory_id и возвращает то же количество элементов без filter(port_inventory_id=999999)

Код:

items = Item.objects.filter(date__range=(date_from, date_to)).filter(port_inventory_id=999999)

Запрос:

SELECT "myapp_item"."id", "myapp_item"."name", "myapp_item"."description", "myapp_item"."date", "myapp_item"."port_inventory_id" FROM "myapp_item" WHERE ("myapp_item"."date" BETWEEN 2024-07-12 10:23:02.248130 AND 2024-08-01 10:23:02.248138 AND "myapp_item"."port_inventory_id" = 999999)

Я также попробовал сделать один вызов фильтра с двумя фильтрами

Код:

items = Item.objects.filter(date__range=(date_from, date_to), port_inventory_id=999999)

Запрос:

SELECT "myapp_item"."id", "myapp_item"."name", "myapp_item"."description", "myapp_item"."date", "myapp_item"."port_inventory_id" FROM "myapp_item" WHERE ("myapp_item"."date" BETWEEN 2024-07-12 10:12:43.089380 AND 2024-08-01 10:12:43.089389 AND "myapp_item"."port_inventory_id" = 999999)

А также реверс

Код:

items = Item.objects.filter(port_inventory_id=999999, date__range=(date_from, date_to))

Запрос:

SELECT "myapp_item"."id", "myapp_item"."name", "myapp_item"."description", "myapp_item"."date", "myapp_item"."port_inventory_id" FROM "myapp_item" WHERE ("myapp_item"."date" BETWEEN 2024-07-12 10:16:14.734102 AND 2024-08-01 10:16:14.734110 AND "myapp_item"."port_inventory_id" = 999999)

Единственный способ, которым это работает, таков:

Код:

items = Item.objects.filter(port_inventory_id=999999).filter(date__range=(date_from, date_to))

Запрос:

SELECT "myapp_item"."id", "myapp_item"."name", "myapp_item"."description", "myapp_item"."date", "myapp_item"."port_inventory_id" FROM "myapp_item" WHERE ("myapp_item"."port_inventory_id" = 999999 AND "myapp_item"."date" BETWEEN 2024-07-12 10:11:23.168955 AND 2024-08-01 10:11:23.168965)

Работает только в том случае, если сначала запрашивается port_inventory_id. Я не ожидал, что результат изменится таким образом.

Любая помощь будет принята с благодарностью...

Не уверен, что решил вашу проблему, но в нашем проекте мы тоже столкнулись с проблемой __range. Мы решили ее глупым и простым способом (KISS). Для вашего случая решение может быть таким:

items = Item.objects.filter(port_inventory_id=999999, date__gte=date_from, date__lte=date_to)

Я рекомендую создать запрос, а затем применить его к набору запросов:

query = {'port_inventory_id':999999, 'date__gte': date_from, 'date__lte': date_to}
items = Item.objects.filter(**query)

А для более сложных запросов я предлагаю использовать помощник запросов Q:

query = Q(port_inventory_id=999999) & Q(date__gte=date_from) & Q(date__lte=date_to)
items = Item.objects.filter(query)

Подробнее о Q здесь: https://docs.djangoproject.com/en/5.0/topics/db/queries/#complex-lookups-with-q-objects

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