python - tutorial - El filtro de consulta Django que combina AND y OR con objetos Q no devuelve los resultados esperados
tutorial django (3)
Intento combinar AND y OR en un filtro usando Q objetos. Parece que el | comportarse como un AND. Esto está relacionado con la anotación anterior que se ejecuta en la misma consulta y no como una subconsulta.
¿Cuál es la forma correcta de manejar esto con Django?
modelos.py
class Type(models.Model):
name = models.CharField(_(''name''), max_length=100)
stock = models.BooleanField(_(''in stock''), default=True)
hide = models.BooleanField(_(''hide''), default=False)
deleted = models.BooleanField(_(''deleted''), default=False)
class Item(models.Model):
barcode = models.CharField(_(''barcode''), max_length=100, blank=True)
quantity = models.IntegerField(_(''quantity''), default=1)
type = models.ForeignKey(''Type'', related_name=''items'', verbose_name=_(''type''))
vistas.py
def hire(request):
categories_list = Category.objects.all().order_by(''sorting'')
types_list = Type.objects.annotate(quantity=Sum(''items__quantity'')).filter(
Q(hide=False) & Q(deleted=False),
Q(stock=False) | Q(quantity__gte=1))
return render_to_response(''equipment/hire.html'', {
''categories_list'': categories_list,
''types_list'': types_list,
}, context_instance=RequestContext(request))
consulta SQL resultante
SELECT "equipment_type"."id" [...] FROM "equipment_type" LEFT OUTER JOIN
"equipment_subcategory" ON ("equipment_type"."subcategory_id" =
"equipment_subcategory"."id") LEFT OUTER JOIN "equipment_item" ON
("equipment_type"."id" = "equipment_item"."type_id") WHERE
("equipment_type"."hide" = False AND "equipment_type"."deleted" = False )
AND ("equipment_type"."stock" = False )) GROUP BY "equipment_type"."id"
[...] HAVING SUM("equipment_item"."quantity") >= 1
consulta SQL esperada
SELECT
*
FROM
equipment_type
LEFT JOIN (
SELECT type_id, SUM(quantity) AS qty
FROM equipment_item
GROUP BY type_id
) T1
ON id = T1.type_id
WHERE hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0)
EDITAR : agregué la consulta SQL esperada (sin la unión en equipment_subcategory)
¿Intenta agregar paréntesis para especificar explícitamente su agrupación? Como ya se ha dado cuenta, varios parámetros para filter() solo se unen a través de AND en el SQL subyacente.
Originalmente tenías esto para el filtro:
[...].filter(
Q(hide=False) & Q(deleted=False),
Q(stock=False) | Q(quantity__gte=1))
Si quisieras (A & B) & (C | D), esto debería funcionar:
[...].filter(
Q(hide=False) & Q(deleted=False) &
(Q(stock=False) | Q(quantity__gte=1)))
Esta respuesta es tardía, pero podría ser útil para muchos de los que están por ahí.
[...].filter(hide=False & deleted=False)
.filter(Q(stock=False) | Q(quantity__gte=1))
Esto generará algo similar a
WHERE (hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0))
OK, no hay éxito aquí o en #django. Así que elijo usar una consulta de SQL sin formato para resolver este problema ...
Aquí el código de trabajo:
types_list = Type.objects.raw(''SELECT * FROM equipment_type
LEFT JOIN (
SELECT type_id, SUM(quantity) AS qty
FROM equipment_item
GROUP BY type_id
) T1
ON id = T1.type_id
WHERE hide=0 AND deleted=0 AND (T1.qty > 0 OR stock=0)
'')