Trabalhando com Conjuntos no Django
No Django, os métodos union, intersection, difference e distinct são métodos para manipulação de conjuntos de QuerySets. Eles permitem combinar, interseccionar, subtrair e remover valores duplicados dos resultados de consultas, respectivamente. Para ilustrar, consideramos a seguinte tabela inicial no banco de dados:
| id | name | age |
|---|---|---|
| 1 | Bob | 42 |
| 2 | Tom | 38 |
| 3 | Sam | 28 |
| 4 | Alice | 32 |
| 5 | Tom | 22 |
union
O método union() combina dois ou mais QuerySets, correspondendo ao operador SQL UNION. Por padrão, os resultados são únicos, ou seja, valores duplicados são removidos.
toms = Person.objects.filter(name="Tom")
print(toms.values())
# <QuerySet [{'id': 2, 'name': 'Tom', 'age': 38}, {'id': 5, 'name': 'Tom', 'age': 22}]>
bobs = Person.objects.filter(name="Bob")
print(bobs.values())
# <QuerySet [{'id': 1, 'name': 'Bob', 'age': 42}]>
# Combinação padrão (valores únicos)
people = toms.union(bobs)
print(people.values())
# <QuerySet [{'id': 1, 'name': 'Bob', 'age': 42}, {'id': 2, 'name': 'Tom', 'age': 38}, {'id': 5, 'name': 'Tom', 'age': 22}]>Para inluir valores duplicados, o método union aceita o argumento all=Tru:
# Incluindo valores duplicados
people = toms.values("name").union(bobs, all=True)
print(people)
# <QuerySet [{'name': 'Tom'}, {'name': 'Tom'}, {'name': 'Bob'}]>intersection
O método intersection() retorna objetos presentes em todos os QuerySets fornecidos, equivalente ao operador SQL INTERSECT.
toms = Person.objects.filter(name="Tom")
print(toms.values())
# <QuerySet [{'id': 2, 'name': 'Tom', 'age': 38}, {'id': 5, 'name': 'Tom', 'age': 22}]>
less35 = Person.objects.filter(age__lt=35)
print(less35.values())
# <QuerySet [{'id': 3, 'name': 'Sam', 'age': 28}, {'id': 4, 'name': 'Alice', 'age': 32}, {'id': 5, 'name': 'Tom', 'age': 22}]>
# Interseção dos QuerySets
people = toms.intersection(less35)
print(people.values())
# <QuerySet [{'id': 5, 'name': 'Tom', 'age': 22}]>No exemplo, apenas o registro com id=5 está presente em ambos os QuerySets.
difference
O método difference() retorna os objetos que estão no primeiro QuerySet, mas não nos outros, equivalente ao operador SQL EXCEPT.
toms = Person.objects.filter(name="Tom")
print(toms.values())
# <QuerySet [{'id': 2, 'name': 'Tom', 'age': 38}, {'id': 5, 'name': 'Tom', 'age': 22}]>
less35 = Person.objects.filter(age__lt=35)
print(less35.values())
# <QuerySet [{'id': 3, 'name': 'Sam', 'age': 28}, {'id': 4, 'name': 'Alice', 'age': 32}, {'id': 5, 'name': 'Tom', 'age': 22}]>
# Diferença entre os QuerySets
people = toms.difference(less35)
print(people.values())
# <QuerySet [{'id': 2, 'name': 'Tom', 'age': 38}]>No exemplo, o registro com id=2 está presente no primeiro QuerySet, mas não no segundo, e é retornado como resultado.
distinct()
O método distinct() elimina valores duplicados de um QuerySet. Ele é útil, por exemplo, para obter uma lista de nomes únicos dos usuários.
# Sem distinct
people = Person.objects.values_list("name", flat=True)
print(people)
# <QuerySet ['Bob', 'Tom', 'Sam', 'Alice', 'Tom']>
# Com distinct
people = Person.objects.values_list("name", flat=True).distinct()
print(people)
# <QuerySet ['Bob', 'Tom', 'Sam', 'Alice']>No exemplo acima, distinct() remove o segundo "Tom" do resultado.
Documentação oficial: