En ocasiones, las aplicaciones necesitan trabajar mostrando elementos filtrados por condiciones muy diferentes que en una consulta SQL quedan unidas por ORs. Al realizar estos filtrados en el ORM de Django solemos recurrir a los objetos Q y a los operadores | y &. El problema es que los QuerySets pueden ampliar sus condiciones de forma encadenada y los operadores Q se aplican directamente sobre una llamada a filter o exclude, pero no sobre el resto de condiciones ya existentes de QuerySet. En esos casos puede ser interesante aprovechar una funcionalidad poco conocida de Django: la combinación de QuerySets.

La combinación nos permite unir dos QuerySets de un mismo modelo en base a un operador OR o AND. Eso nos permite obtener listados filtrados con condiciones complejas dejando un código limpio y pensando en términos de la unión o la intersección de los elementos de cada QuerySet. Otra condición para poder combinar dos QuerySets es que los dos tengan la misma condición de unicidad, es decir, que si uno tiene un distinct aplicado, el otro también deberá tenerlo.

  Model.objects.filter(attra=True) | Model.objects.filter(attrb=True)

Internamente, esta funcionalidad se basa en la utilización del objeto query, instancia de la clase Query usada por Django para representar un consulta SQL, que tiene todo QuerySet. Así, al combinar dos QuerySets lo que estamos haciendo realmente es combinar sus objetos Query, que a su vez generan la consulta SQL a la base de datos. En definitiva, la combinación fusiona las condiciones del WHERE de los dos QuerySets utilizando el operador aplicado y generando el SQL necesario para obtenerlos.

blog comments powered by Disqus