Как отфильтровать набор запросов на основе связанных объектов, если он содержит данные в django

Я хочу фильтровать и получать только те данные, которые относятся к данным связанных объектов, если только данные, связанные с его дочерними объектами родительского объекта, имеют данные. Например: у меня есть следующие модели:

class Collection(models.Model):
    date_of_collection=models.DateField()

class Product(models.Model):
    name=models.CharField(max_length=100)
    collection = models.ForeignKey(Collection)

class Price(models.Model):
    price = models.FloatField()
    products = models.ForeignKey(Products, on_delete=models.CASCADE)

и у меня есть данные, связанные с моделями, как:

Collection:
+----+--------------------+
| id | date_of_collection |
+----+--------------------+
|  1 | 2019-01-17         |
|  2 | 2019-01-30         |
|  3 | 2019-02-01         |
|  4 | 2019-02-02         |
+----+--------------------+

Products:

 +----+--------------------------------+
 | id | name           | collection    |
 +----+--------------------------------+
 |  1 | product 1      | 3             |
 |  2 | product 2      | 1             |
 |  3 | product 3      | 1             |
 |  4 | product 4      | 4             |
 +----+--------------------------------+

Price:

| id     | price            | product               |
+--------+------------------+-----------------------+
| 1      | 10.00            | 1                     |
| 2      | 20.00            | 1                     |
| 3      | 12.00            | 3                     |
+--------+------------------+-----------------------+

здесь у меня есть цена, связанная только с продуктом 1 и 3, поэтому мне нужны только те продукты, основанные на наборе запросов, которые я хочу фильтровать только на основе определенной даты_из_коллекции.

Я пробовал следующий набор запросов:

collection_month = Collection.objects.filter(date_of_collection__month=2)
product = Product.objects.filter(collection_id__in=collection_month).exclude(price_set__price=None)

это так, как я делаю или как-то по-другому .. иногда это дает плохой результат. Как это сделать.


person Dipesh Bajgain    schedule 22.05.2019    source источник


Ответы (1)


Вы довольно близко.
Не следует сравнивать collection_id с реальными предметами коллекции — вы можете просто передать collection__in=collection_month.
Вы можете напрямую исключить продукты без price с price__isnull=True

Этот запрос будет использовать подзапрос (WHERE):

collection_month = Collection.objects.filter(date_of_collection__month=2)
products = Product.objects.filter(collection__in=collection_month).exclude(price__isnull=True)

Этот запрос будет использовать INNER JOIN, который по слухам, быстрее:

products = Product.objects.filter(collection__date_of_collection__month=2).exclude(price__isnull=True)
person Gasanov    schedule 22.05.2019
comment
Спасибо за ваш ответ, моя база данных имеет некоторые условия, которые действительно требуют collection__in для проверки данных. Я надеюсь, что .exclude(price__isnull=True не сработает, мы должны использовать price_set__price__isnull=True, иначе мы получим django.core.exceptions.FieldError - person Dipesh Bajgain; 22.05.2019
comment
@dipbazz ты действительно проверял результаты? На моем конце работает нормально. Я могу отправить вам мой модульный тест, который показывает, что он работает. - person Gasanov; 22.05.2019
comment
Это также работает для меня, но дело в том, что я должен использовать related_name__fields для поиска связанных с ним объектов. Я просто не могу получить доступ к полям дочерних объектов напрямую из родительских объектов. - person Dipesh Bajgain; 22.05.2019
comment
@dipbazz Можете ли вы привести пример того, в каком запросе вы не можете получить доступ к полям дочерних объектов из родительских объектов? Что вы хотите получить? - person Gasanov; 22.05.2019
comment
Поскольку я установил свой related_name в полях внешнего ключа ценовых моделей, мой related_query_name по умолчанию будет иметь значение related_name, как указано в documentaion of django Итак, я должен использовать связанное имя вместо имени модели в поиске. - person Dipesh Bajgain; 22.05.2019