Django-native/ORM подход к самостоятельному присоединению

Пытаюсь настроить Django-native запрос, который захватывает все строки/отношения, когда он появляется на другой стороне отношения "многие ко многим".

Я могу объяснить на примере:

# Django models

class Ingredient:
    id = ...
    name = ...
    ...

class Dish:
    id = ...
    name = ...
    ...

class IngredientToDish
    # this is a many to many relationship
    ingredient_id = models.ForeignKey("Ingredient", ...)
    dish_id = models.ForeignKey("Dish", ...)
    ...

Хотелось бы получить Django-нативный способ: "Для каждого блюда, в котором используется помидор, найдите все ингредиенты, которые в нем используются". Ищу список строк, который выглядит примерно так:

(cheese_id, pizza_id)
(sausage_id, pizza_id)
(tomato_id, pizza_id)
(cucumber_id, salad_id)
(tomato_id, salad_id)

Я хотел бы хранить их в одном запросе к БД, для оптимизации. В SQL это был бы простой JOIN с самим собой (IngredientToDish таблица), но я не смог найти, каким должен быть обычный подход в Django... Скорее всего, используется какая-то форма select_related, но я не смог заставить ее работать; я думаю, часть причины в том, что я не смог кратко выразить проблему в словах, чтобы найти нужную документацию во время исследования.

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

Вы можете .filter(…) [Django-doc] с:

Ingredient.objects.filter(
    ingredienttodish__dish_id__ingredienttodish__ingredient_id__name='Tomato'
)

Вы также можете добавить первичный ключ блюда, для которого это удерживается с:

from django.db.models import F

Ingredient.objects.filter(
    ingredienttodish__dish_id__ingredienttodish__ingredient_id__name='Tomato'
).annotate(
    dish_id=F('ingredienttodish__dish_id')
)

Объекты Ingredient, возникающие в результате этого QuerySet будут иметь дополнительный атрибут dish_id, содержащий первичный ключ Dish, для которого они были использованы.


Примечание: Обычно не добавляют суффикс …_id к полю ForeignKey, так как Django автоматически добавит поле-"близнец" с суффиксом …_id. Поэтому он должен быть dish, вместо dish_id.

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