Introdução

O mapeador objeto-relacional (ORM) no Django torna mais fácil para os desenvolvedores serem produtivos sem conhecimento prévio de trabalho em bancos de dados e SQL. QuerySets representam uma coleção de objetos do banco de dados e podem ser construídos, filtrados, divididos ou geralmente repassados ​​sem realmente atingir o banco de dados. Nenhuma atividade de banco de dados ocorre até que façamos algo para avaliar o QuerySet. Neste guia, você aprenderá como realizar essas consultas, básicas e avançadas.

Ao longo do guia, iremos consultar o modelo django.contrib.auth.models.User . Você pode inserir vários usuários neste modelo para testar diferentes QuerySets discutidos no guia a seguir.

Além disso, usaremos o shell do Django para executar e testar as consultas. Você pode iniciar o shell Django com o seguinte:

shell

 python manage.py

Consultas básicas

Vamos começar com algumas operações básicas de QuerySet.

Recuperando objetos únicos

Para casos em que você sabe que há apenas um único objeto que corresponde à consulta, você pode usar o método get () , que retornará o objeto. Ao contrário de filter , que sempre retorna o QuerySet :

 >>> user_id_1=User.objects.get (id=1)

Observe que se nenhum resultado for encontrado, ele gerará uma exceção DoesNotExist , então é melhor usá-lo no bloco try-except:

 tente:
user_id_1=User.objects.get (id=1)
exceto User.DoesNotExist:
imprimir ("Usuário com id não existe")

Obtendo um objeto do QuerySet

Existem duas opções para obter um objeto do QuerySet.

O primeiro está usando first () e last () . First () retorna o primeiro objeto correspondido ao QuerySet, e last () retorna o último objeto correspondido ao QuerySet:

 from django.contrib.auth.models import User >>> User.objects.filter (is_active=True).first () >>> User.objects.filter (is_active=True).last ()

A consulta acima retornará o primeiro e o último objeto correspondente ao Queryset.

A segunda opção é mais recente () e mais antiga () . Latest () retorna o objeto mais recente na tabela com base nos campos fornecidos, e mais antigo retorna o objeto mais antigo na tabela com base nos campos fornecidos:

 from django.contrib.auth.models import User >>> User.objects.latest ('date_joined') >>> User.objects.earliest ('date_joined')

Pesquisas de campo

As pesquisas de campo tratam de como você especifica a cláusula SQL WHERE . Os argumentos de palavra-chave de pesquisa básica assumem a forma field__lookuptype=value . Por exemplo:

 de datetime import datetime
## Obtenha todos os usuários cujo date_joined é menor que a data de hoje.
>>> User.objects.filter (date_joined__lte=datetime.today ())

Pesquisando a string específica (diferencia maiúsculas de minúsculas):

 ## Obtém todos os usuários cuja string de nome de usuário contém"usuário"
>>> User.objects.filter (username__contains="usuário")

Ou não diferencia maiúsculas de minúsculas:

 ## Obter todos os usuários cuja string de nome de usuário contém"usuário"(não diferencia maiúsculas de minúsculas)
>>> User.objects.filter (username__icontains="usuário")

Ou começa com e termina com a pesquisa:

 ## Obter todos os usuários cuja string de nome de usuário comece com"usuário"
>>> User.objects.filter (username__startswith="user")
## Pega todos os usuários cuja string de nome de usuário termina com"usuário"
>>> User.objects.filter (username__endswith="usuário")

Você também pode usar versões que não diferenciam maiúsculas de minúsculas chamadas istartswith e iendswith .

Ordenando QuerySets

Depois de filtrar o QuerySet, você pode ordená-lo em ordem crescente ou decrescente com base nos campos fornecidos.

A consulta a seguir primeiro filtrará os usuários com base em is_active , depois por nome de usuário em ordem crescente e, finalmente, por date_joined em ordem decrescente. Observe que - indica a ordem decrescente de date_joined :

 from django.contrib.auth.models import User >>> User.objects.filter (is_active=True).order_by ('nome de usuário','-date_joined')

Filtros de encadeamento

O Django oferece a opção de adicionar vários filtros para encadear refinamentos juntos:

 import datetime
from django.contrib.auth.models import User >>> User.objects.filter (
... username__startswith='usuário'
...).filter (
... date_joined__gte=datetime.date.today ()
... ).excluir(
... is_active=False
...)

A consulta acima inicialmente leva todos os usuários, adiciona dois filtros e exclui um. O resultado final é um QuerySet contendo todos os usuários cujo username começa com user , seu date_joined sendo maior ou igual à data de hoje e, finalmente, exclui os usuários inativos.

Consultas avançadas

Agora que você entende as operações básicas de QuerySet, vamos pular para consultas avançadas e operações de QuerySet.

Definir operações

Union () usa o operador SQL UNION para combinar os resultados de dois ou mais QuerySets:

 >>> qs1.union (qs2, qs3,...)

Intersection () usa o operador SQL INTERSECTION para encontrar resultados comuns (compartilhados) de dois ou mais QuerySets:

 >>> qs1.intersection (qs2, qs3,...)

Difference () usa o operador SQL EXCEPT para encontrar elementos presentes no QuerySet, mas não em alguns outros QuerySets:

 >>> qs1.difference (qs2, qs3,...)

objetos Q

Um objeto Q () representa uma condição SQL que pode ser usada em operações relacionadas ao banco de dados. Se você deseja executar consultas complexas que contêm as instruções OR , AND e NOT , você pode usar Q () objetos:

 >>> de django.db.models import Q >>> Q (username__startswith='user')

Por exemplo, vamos encontrar todos os usuários que são funcionários ou superusuários:

 >>> from django.contrib.auth.models import User >>> User.objects.filter (Q (is_staff=True) | Q (is_superuser=True))

Da mesma forma, você pode usar AND e NOT . Na consulta abaixo, ele encontra todos os usuários que são funcionários e cujos nomes de usuário não começam com usuário :

 >>> User.objects.filter (Q (is_staff=True) & ~ Q (username__startswith='user'))

Objetos F

O objeto F () representa o valor de um campo de modelo ou coluna anotada. Torna possível referir-se a valores de campo de modelo e realizar operações de banco de dados usando-os sem realmente ter que retirá-los do banco de dados para a memória Python.

Vejamos um exemplo de incremento de uma contagem de hits em um com o modelo HitCount de id=1 .
Normalmente, uma maneira óbvia é salvá-lo na memória, incrementar a contagem e salvá-lo:

 site=HitCount.objects.get (id=1)
site.hits +=1
site.save ()

A outra maneira de lidarmos com isso inteiramente pelo banco de dados é introduzindo os objetos F () . Quando o Django encontra uma instância de F () , ele sobrescreve os operadores Python padrão para criar uma expressão SQL encapsulada:

 de django.db.models import F site=HitCount.objects.get (id=1)
site.hits=F ('hits') + 1
site.save ()

F () oferece vantagens de desempenho por:

  • Fazer com que o banco de dados, em vez do Python, execute operações
  • Reduzir o número de consultas que algumas operações exigem

Execução de consultas SQL brutas

O Django oferece duas maneiras de realizar consultas SQL brutas usando raw () e connection.cursor () .

Para maior clareza, vamos fazer uma consulta básica sobre como buscar os usuários que não são da equipe:

 from django.contrib.auth.models import User User.objects.filter (is_staff=False)

Execução de consultas brutas

Raw () pega uma consulta SQL bruta, a executa e retorna uma instância RawQuerySet , que pode ser iterada como um QuerySet normal para fornecer instâncias de objeto:

 query="selecione * from auth_user onde is_staff=False;"
resultados=User.objects.raw (consulta)
para resultado em resultados:
imprimir (resultado)

Executando o SQL personalizado diretamente

Às vezes, mesmo raw não é suficiente; você pode precisar realizar consultas que não mapeiam de forma clara para os modelos ou executar diretamente as consultas UPDATE , INSERT ou DELETE . Nesses casos, você sempre pode acessar o banco de dados diretamente, roteando inteiramente a camada do modelo.

Por exemplo, você pode executar a consulta SQL acima usando o cursor, conforme demonstrado abaixo:

 da conexão de importação django.db query="selecione * from auth_user onde is_staff=False;"
com connection.cursor () como cursor:
cursor.execute (consulta)
imprimir (cursor.fetchall ())

Consulte mais sobre este tópico na documentação do Django aqui .

Obtendo SQL bruto para um determinado QuerySet

Para obter a consulta SQL bruta de um Django QuerySet, o atributo .query pode ser usado. Isso retornará o objeto django.db.models.sql.query.Query , que então pode ser convertido em uma string usando __str __ () :

 >>> queryset=MyModel.objects.all ()
>>> queryset.query.__ str __ ()
from django.contrib.auth.models import User >>> queryset=User.objects.all ()
>>> queryset.query
 >>> queryset.query.__ str __ () 'SELECT"auth_user"."Id","auth_user"."Password","auth_user"."Last_login","auth_user"."Is_superuser","auth_user"."Username","auth_user"."First_name","auth_user"."last_name","auth_user"."email","auth_user"."is_staff","auth_user"."is_active","auth_user"."date_joined"FROM"auth_user"'

Agregação

O agrupamento por consultas é uma operação SQL bastante comum e às vezes se torna uma fonte de confusão quando se trata de ORM. Nesta seção, vamos nos aprofundar na aplicação de GROUP BY e agregações.

GROUP BY básico e agregações

Vamos começar com as operações básicas de contagem, que retornarão o dict contendo a contagem de usuários:

 >>> User.objects.aggregate (total_users=Count ('id'))

Usando anotações

Aggregate é usado para agregar a tabela inteira. Na maioria das vezes, queremos aplicar as agregações a grupos de linhas e, para isso, pode-se usar annotate .

Vejamos um exemplo para agrupar usuários com base em is_staff :

 >>> User.objects.values ​​("is_staff"). annotate (user_count=Count ('*')

Para realizar o agrupamento no estilo ORM, temos que usar os dois métodos valores e annotate da seguinte maneira:

  • values ​​(
    )
    : mencione os campos pelos quais agrupar
  • annotate () : mencione o que agregar usando funções como SUM , COUNT , MAX , MIN e AVG

Múltiplas agregações e campos

Para várias agregações, precisamos adicionar vários campos pelos quais você deseja agrupar. No exemplo abaixo, executamos um grupo de consulta por colunas ( is_active , is_staff ):

 >>> User.objects.values ​​("is_active","is_staff"). annotate (user_count=Count ("*"))

Cláusula HAVING

A cláusula HAVING é usada para filtrar grupos. Na consulta a seguir, filtramos o grupo que possui uma contagem maior que um:

 >>> User.objects.values ​​("is_staff"). annotate (user_count=Count ("*")). filter (user_count__gt=1)

A consulta SQL equivalente é:

 SELECT is_staff, COUNT (*) AS user_count
FROM auth_user
GROUP BY is_staff
TENDO CONTAGEM (*)> 1;

Conclusão

Neste guia, discutimos vários métodos de QuerySets e como trabalhar com diferentes consultas. Com algum cuidado e compreensão dos conceitos simples por trás dos QuerySets do Django, você pode melhorar seu código e se tornar um desenvolvedor Django melhor. Você sempre pode consultar a documentação do Queryset e a Documentação de agregação para estudo posterior.

A postagem QuerySets e agregações em Django apareceu primeiro em LogRocket Blog .

Source link