with tutorial latest framework espaƱol desde con cero applications python django django-q

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) '')