Как применить фильтр для каждой строки одного и того же набора запросов на Django
У меня есть модель Product, которая имеет отношение с самой собой, используя ключ "parent".
Таким образом, чтобы получить родительский продукт, я просто делаю product.parent
, а если мне нужны дочерние продукты, я делаю product.product_set.all()
.
Я хочу сделать аннотацию на наборе родительских продуктов и суммировать запас каждого продукта с запасами его дочерних продуктов. Что-то похожее на это:
qs = Product.objects.filter(is_parent=True)
qs = qs.annotate(stock_sum=Sum(Product.objects.filter(parent_id=F('id')).values_list['stock']))
Возможно ли это? Приведет ли это к большому количеству запросов или django знает способ справиться с этим с помощью нескольких джойнов?
За исключением одной синтаксической ошибки (квадратные скобки вместо круглых после values_list
) это должно работать так, как вы задумали.
Это вызывает только один запрос. Обратите внимание, что вы можете проверить SQL, который генерирует ORM, обратившись к свойству .query
в наборе запросов (следующее было впоследствии прогнано через SQL pretty-printer):
>>> str(qs.query)
SELECT
"yourapp_product"."id",
"yourapp_product"."parent_id",
"yourapp_product"."stock",
SUM((SELECT U0."stock" FROM "yourapp_product" U0 WHERE U0."parent_id" = (U0."id"))) AS "stock_sum"
FROM
"yourapp_product"
WHERE
"yourapp_product"."is_parent"
GROUP BY
"yourapp_product"."id",
"yourapp_product"."parent_id",
"yourapp_product"."stock";
Не уверен, как решить проблему с помощью Django ORM.
Но в SQL вы можете сделать это следующим образом:
SELECT
p.id,
(
SELECT
SUM(c.stock)
FROM
products_product c
WHERE
c.parent_id = p.id) + p.stock as stock_sum
FROM
products_product p
WHERE
p.parent_id is null
Вы можете выполнить sql-запрос в Django следующим образом:
products = Product.objects.raw("""
SELECT
p.id,
(
SELECT
SUM(c.stock)
FROM
products_product c
WHERE
c.parent_id = p.id) + p.stock as stock_sum
FROM
products_product p
WHERE
p.parent_id is null
""")
и затем использовать его, например, так [(p.id, p.stock_sum) for p in products]