QuerySets e ORM do Django
Neste capítulo você vai aprender como o Django se conecta ao banco de dados e como ele armazena dados. Vamos nessa!
O que é um QuerySet?
Um QuerySet (conjunto de busca) é, em essência, uma lista de objetos de um dado modelo. QuerySet permite que você leia os dados a partir de uma base de dados, filtre e ordene.
É mais fácil aprender usando exemplos. Vamos lá?
O Shell do Django
Abra o seu terminal (não o PythonAnywhere) e digite o seguinte comando:
command-line
(myvenv) ~/djangogirls$ python manage.py shell
O resultado deve ser:
command-line
(InteractiveConsole)
>>>
Agora você está no console interativo do Django. Ele é como o prompt do Python, só que com umas mágicas adicionais ;). Você pode usar todos os comandos do Python aqui também, é claro.
Todos os objetos
Primeiro, vamos tentar mostrar todas as nossas postagens. Podemos fazer isso com o seguinte comando:
command-line
>>> Post.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'Post' is not defined
Oops! Um erro apareceu. Ele nos diz que não existe algo chamado Post. É verdade -- nós esquecemos de importá-lo antes!
command-line
>>> from blog.models import Post
Mas isso é simples: basta importar o modelo Post
de dentro do blog.models
. Vamos tentar mostrar todas as postagens novamente:
command-line
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>]>
É uma lista dos posts que criamos mais cedo! Nós criamos estes posts utilizando a interface do Django admin. No entanto, agora queremos criar novos posts utilizando Python. Como fazemos isso?
Criando um objeto
É assim que se cria um objeto Post no banco de dados:
command-line
>>> Post.objects.create(author=me, title='Sample title', text='Test')
Mas aqui temos um ingrediente faltando: me
. Precisamos passar uma instância do modelo User
como autor. Como fazemos isso?
Primeiro vamos importar o modelo User:
command-line
>>> from django.contrib.auth.models import User
Quais usuários temos no nosso banco de dados? Experimente isso:
command-line
>>> User.objects.all()
<QuerySet [<User: ola>]>
Este é o superusuário que criamos anteriormente! Vamos pegar uma instância do usuário agora (ajuste esta linha para usar seu próprio nome de usuário):
command-line
>>> me = User.objects.get(username='ola')
Como você pode ver, agora obtém
um Usuário
com um nome de usuário
que é igual a 'ola'. Arrumado!
Agora finalmente podemos criar nosso post:
command-line
>>> Post.objects.create(author=me, title='Sample title', text='Test')
<Post: Sample title>
Uhuu! Quer ver se funcionou?
command-line
>>> Post.objects.all()
<QuerySet [<Post: my post title>, <Post: another post title>, <Post: Sample title>]>
É isso aí, mais um post na lista!
Adicionando mais postagens
Agora você pode se divertir um pouco e adicionar algumas postagens para ver como funciona. Adicione mais uns 2 ou 3 posts pelo Python e siga para a próxima parte.
Filtrando objetos
Um recurso importante dos QuerySets é a possibilidade de filtrá-los. Digamos que queremos encontrar todos as postagens escritas pela usuária ola. Para isto, usamos filter
ao invés de all
em Post.objects.all()
. Entre parênteses, indicamos quais condições precisam ser atendidas por um post para que ele entre no nosso queryset. No nosso caso, a condição é: author
é igual a me
. A maneira de escrever isso no Django é: author=me
. Agora o nosso trecho de código ficará assim:
command-line
>>> Post.objects.filter(author=me)
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>
E se quisermos ver todos os posts que contenham a palavra 'title' no campo title
?
command-line
>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>, <Post: 4th title of post>]>
Observação: Existem dois caracteres de sublinhado (
_
) entretitle
econtains
. O ORM do Django utiliza esta sintaxe para separar nomes de campo ("title") e operações ou filtros (como "contains"). Se você usar apenas um sublinhado, obterá um erro como "FieldError: Cannot resolve keyword title_contains".
Você também pode obter uma lista de todos os posts publicados. Fazemos isso filtrando todos os posts com uma published_date
definida no passado:
command-line
>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>
Infelizmente, o post que nós criamos pelo console do Python não está publicado ainda. Podemos mudar isso! Primeiro, busque a instância do post que queremos publicar:
command-line
>>> post = Post.objects.get(title="Sample title")
Então vamos publicá-lo com o nosso método publish
:
command-line
>>> post.publish()
Agora, busque novamente a lista de posts publicados (aperte a seta para cima algumas vezes e pressione enter
):
command-line
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet [<Post: Sample title>]>
Ordenando objetos
Um QuerySet também nos permite ordenar a lista de objetos. Vamos tentar ordenar as postagens pelo campo created_date
:
command-line
>>> Post.objects.order_by('created_date')
<QuerySet [<Post: Sample title>, <Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>]>
Também podemos inverter a ordem adicionando -
no início:
command-line
>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: 4th title of post>, <Post: My 3rd post!>, <Post: Post number 2>, <Post: Sample title>]>
Consultas Complexas com Encadeamento de Métodos
Como você viu, alguns métodos em Post.objects
retornam um QuerySet. Esses mesmos métodos podem, por sua vez, ser invocados num QuerySet, o que resultará num novo QuerySet. Dessa forma, você pode combinar seus efeitos encadeando-los juntos:
>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Post number 2>, <Post: My 3rd post!>, <Post: 4th title of post>, <Post: Sample title>]>
Isso é muito poderoso e nos permite criar consultas bastante complexas.
Legal! Você já está pronta para a próxima parte! Para fechar o terminal, digite:
command-line
>>> exit()
$