Django Filters – o?

¿Cómo haría un “o” en un filtro django?

Básicamente, quiero poder enumerar los elementos que un usuario ha agregado (están listados como el creador) o el elemento ha sido aprobado.

así que básicamente necesito seleccionar

item.creator = owner or item.moderated = False 

¿Cómo haría esto en django (preferiblemente con un filtro / conjunto de preguntas)

Hay objetos Q que permiten búsquedas complejas. Ejemplo:

 from django.db.models import Q Item.objects.filter(Q(creator=owner) | Q(moderated=False)) 

Puedes usar el | operador para combinar querysets directamente sin necesidad de objetos Q:

 result = Item.objects.filter(item.creator = owner) | Item.objects.filter(item.moderated = False) 

(edit – Inicialmente, no estaba seguro de si esto causaba una consulta extra, pero @spookylukey señaló que la evaluación del conjunto de preguntas perezosa se ocupa de eso)

Desea que el filtro sea dynamic, entonces debe usar Lambda como

 from django.db.models import Q brands = ['ABC','DEF' , 'GHI'] queryset = Product.objects.filter(reduce(lambda x, y: x | y, [Q(brand=item) for item in brands])) 

reduce(lambda x, y: x | y, [Q(brand=item) for item in brands]) es equivalente a

 Q(brand=brands[0]) | Q(brand=brands[1]) | Q(brand=brands[2]) | ..... 

Vale la pena señalar que es posible agregar expresiones Q.

Por ejemplo:

 from django.db.models import Q query = Q(first_name='mark') query.add(Q(email='mark@test.com'), Q.OR) query.add(Q(last_name='doe'), Q.AND) queryset = User.objects.filter(query) 

Esto termina con una consulta como:

 (first_name = 'mark' or email = 'mark@test.com') and last_name = 'doe' 

De esta forma no hay necesidad de tratar con operadores, reducciones, etc.

Similar a answera más viejo, pero un poco más simple, sin el lambda:

 filter_kwargs = { 'field_a': 123, 'field_b__in': (3, 4, 5, ), } 

Para filtrar estas dos condiciones usando OR :

 Item.objects.filter(Q(field_a=123) | Q(field_b__in=(3, 4, 5, )) 

Para obtener el mismo resultado programáticamente:

 list_of_Q = [Q(**{key: val}) for key, val in filter_kwargs.items()] Item.objects.filter(reduce(operator.or_, list_of_Q)) 

(roto en dos líneas aquí, para mayor claridad)

operator está en la biblioteca estándar: import operator
De docstring:

or_ (a, b) – Igual que a | segundo.

Para Python3, reduce no está en la biblioteca estándar: from functools import reduce


PD

No se olvide de asegurarse de que list_of_Q no esté vacío; reduce() se ahogará en la lista vacía, necesita al menos un elemento.

Esto podría ser útil https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

Básicamente parece que actúan como O