Dados estos modelos:
from django.db import models class Foo(models.Model): pass # table with only one column, ie a primary key 'id' of type integer class Bar(models.Model): value = models.TextField() foo = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bars') ¿Cómo crear un filtro que devuelva todos los Foo relacionados con al menos una Bar con un value distinto de cero ?
Soy consciente de que es posible seleccionar primero las Bar distintas de cero y luego devolver las Foo relacionadas con ellas. Pero estoy buscando específicamente una solución que obtenga directamente los Foo s relevantes en un QuerySet. La razón es que podría aplicarse fácilmente a las relaciones anidadas en un nivel más profundo.
Es sencillo crear un QuerySet que devuelva todos los Foo relacionados con al menos una Bar con un value cero :
Foo.objects.filter(bars__value="zero")Sin embargo, debido a la falta del operador "no igual" en los métodos de filtro de Django, es imposible hacer algo como esto:
Foo.objects.filter(bars__value__not_equal="zero") # Unsupported lookup 'not_equal' for TextField Usando exclude :
Foo.objects.exclude(bars__value="zero") no produce la salida deseada porque excluye todos los Foo que se relacionan con al menos una Bar con un valor cero.
Por lo tanto, si un Foo está relacionado con dos Bar s, uno de los cuales tiene un value cero y el otro tiene un value distinto de cero, sería filtrado por esta exclude . Sin embargo, la intención es incluirlo porque está relacionado con al menos una Bar con un valor distinto de cero.
De manera similar, usando el objeto Q negado:
Foo.objects.filter(~models.Q(bars__value="zero")) tampoco produce la salida deseada porque solo incluiría todos los Foo s que no están relacionados con ningún Bar s con un valor cero.
Crearía el mismo QuerySet que el método de exclude mencionado anteriormente.
El tipo del campo B.value se eligió intencionalmente como texto en los ejemplos para enfatizar que estoy buscando una solución genérica en la que el operador "distinto" no se pueda emular usando, por ejemplo, una combinación de "menor que" y "mayor". que" operadores.
Tampoco puedo pensar en una forma simple de lograr esto, pero usar una Subquery para excluir las Bar de valor cero podría funcionar:
from django.db.models import Subquery qs = Foo.objects.filter( bars__pk__in=Subquery(Bar.objects.exclude(value="zero").values('pk')) ) Esto debería proporcionarle todas las instancias de Foo con una relación con un Bar con un valor distinto de cero.