#python #mysql #django #django-models
#python #mysql #django #django-модели
Вопрос:
Я использую Django ORM с MySQL и трачу много времени на запросы. Для некоторых «продвинутых» случаев я решил использовать необработанные запросы, поскольку для них я не мог сделать это с помощью аннотаций. Проблема с необработанными запросами заключается в том, что они не добавляют «поле» в набор запросов, например аннотации или агрегации. Итак, я использую extra. Но теперь я столкнулся с проблемой:
qs_products = Productos.objects.all()
qs_productos.extra({
"stock":
"""
SELECT SUM(items.cantidad)
FROM
`encargosProveedor_listado_articulos` AS encargos,
`itemArticulosProveedor`AS items, `articulos` as articulos
WHERE
encargos.itemarticulosproveedor_id=items.id and
articulos.id=items.articulos_id
GROUP BY articulos.producto_id
"""
})
Это результат для этого запроса непосредственно от моего администратора БД:
---------------------
| SUM(items.cantidad) |
---------------------
| 14 |
---------------------
| 4 |
---------------------
Но при запуске этого кода в django с использованием extra()
MySQLdb._exceptions.OperationalError: (1242, ‘Подзапрос возвращает более 1 строки’)
В чем проблема возврата более одной строки?Запрос возвращает две строки, потому что у меня есть два продукта, это разумно. Я хочу назначить запас для каждого из продуктов.
Альтернативы? Предложения? Подсказки?
Ответ №1:
Вы пытаетесь выполнить соединение между внешним запросом и extra
подзапросом, и для этого базе данных требуется явное предложение join . Я полагаю, вы можете добавить предложение WHERE, чтобы extra
оно работало:
qs_productos.extra({
"stock":
"""
SELECT SUM(items.cantidad)
FROM
`encargosProveedor_listado_articulos` AS encargos,
`itemArticulosProveedor`AS items, `articulos` as articulos
WHERE
articulos.producto_id = productos.id and
encargos.itemarticulosproveedor_id=items.id and
articulos.id=items.articulos_id
GROUP BY articulos.producto_id
"""
})
productos
in articulos.producto_id = productos.id
нужно было бы заменить фактическим именем таблицы из основного запроса.
Поскольку extra
он устарел (еще не совсем устарел, хотя начиная с Django 2.2), вот эквивалентный RawSQL
запрос:
qs_productos.annotate(stock=RawSQL(
"""
SELECT SUM(items.cantidad)
FROM
`encargosProveedor_listado_articulos` AS encargos,
`itemArticulosProveedor`AS items, `articulos` as articulos
WHERE
articulos.producto_id = productos.id and
encargos.itemarticulosproveedor_id=items.id and
articulos.id=items.articulos_id
GROUP BY articulos.producto_id
""",
()
))
Пустой кортеж в RawSQL
требуется, поскольку функция принимает params
аргумент кортежа, который не является необязательным, даже если у вас нет параметров для передачи.
В качестве бонуса RawSQL
менее чувствителен к предыдущим values
вызовам и output_field
при необходимости предлагает необязательный параметр.
Комментарии:
1. Спасибо! Это сработало. Но все же я не получаю поле ‘stock’ в своем наборе запросов. Вы знаете, почему?
2. Единственная причина, о которой я могу думать, — это использовать
values()
beforeextra()
, и в этом случаеextra
поле автоматически отбрасывается .3. Нет, я использую values() после запроса, чтобы показать / посмотреть, есть ли запасное поле.
4. Затем вам нужно будет отладить ошибку, которая скрывается где-то в вашем коде. Или вы можете попробовать
RawSQL
альтернативу, предложенную выше, возможно, это устранит проблему.