Como utilizar Class Based Views (CBV) no Django

Cansado de programar?

Cansado(a) de quebrar a cabeça para aprender a programar Python de verdade?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Suporte

Projetos práticos voltados para o mercado de trabalho

Suporte

Formação moderna com foco na prática profissional

Salve salve Pythonista Web!

Se você é um desenvolvedor de Django em busca de uma maneira mais eficiente e organizada de desenvolver suas views, as Class Based Views podem ser exatamente o que você precisa.

As Class Based Views são um recurso poderoso, que permitem uma abordagem Orientada a Objetos para a construção de suas Views.

Isso significa que, ao invés de criar funções separadas para cada view em seu projeto, você pode utilizar classes para definir suas views, tornando seu código mais legível e fácil de manter.

Com as Class Based Views, você tem acesso a diversas funcionalidades que não estão disponíveis nas views baseadas em funções, como herança, mixins e atributos de classe.

Neste artigo, vamos explorar as vantagens das Class Based Views e como utilizá-las em seu projeto Django.

Então já prepara o café, e vamos nessa! :coffee:

Vá Direto ao Assunto…

Mas primeiro...

Eu disponibilizei gratuitamente a aula introdutória do nosso Curso de Django - que é parte integrante do curso Jornada Python, aqui da Python Academy - e acho que você pode aprender bastante com ela!

Nesse vídeo você vai aprender sobre:

  • Desenvolvimento Frontend vs Backend
  • Arquitetura do Django
  • Por que aprender Django
  • O mercado para o Desenvolvedor Django
  • O salário do Dev Django trabalhando para fora
  • Quais empresas utilizam o Django

É só clicar na imagem abaixo para assistir o vídeo!

Introdução às Class Based Views do Django

Neste artigo, nós vamos trabalhar em cima do nosso HelloWorld, um projeto de gerenciamento de funcionários.

Caso você ainda não o conheça, sugiro que visite o nosso primeiro post sobre a Camada Model do Django, onde desenvolvemos a base do nosso projeto.

As Class Based Views - ou CBVs, para os íntimos - que vamos estudar hoje, nos ajudam a agilizar o desenvolvimento da nossa aplicação.

Temos basicamente duas formas para utilizá-las.

Primeiro, podemos usá-las diretamente no nosso URLConf (no arquivo urls.py):

1
2
3
4
5
6
from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path('', TemplateView.as_view(template_name="index.html")),
]

E a segunda maneira, sendo a mais utilizada e poderosa, é herdando da View desejada e sobrescrevendo os atributos e métodos na subclasse.

Criação de Templates HTML com a CBV TemplateView

Por exemplo, se você precisar apenas renderizar uma página HTML, podemos utilizar a TemplateView para isso (veja a documentação aqui da TemplateView).

Para isso é necessário 3 passos:

  • Arquivo contendo o código HTML que deve ser renderizado pela TemplateView
  • A TemplateView, propriamente dita.
  • A configuração de rotas configurando qual URL deve ser servida por esta TemplateView

Portanto, se criarmos um arquivo HTML (por exemplo):

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <title>Primeira Template</title>
</head>
<body>
    <h1>Esse template será renderizado pelo Django</h1>
</body>
</html>

Com a seguinte TemplateView:

1
2
3
4
from django.views.generic import TemplateView

class IndexTemplateView(TemplateView):
  template_name = "index.html"

E a seguinte configuração de rotas:

1
2
3
4
5
6
from django.urls import path
from helloworld.views import IndexTemplateView

urlpatterns = [
    path('', IndexTemplateView.as_view()),
]

Teremos um template sendo renderizado no caminho raiz da sua aplicação (geralmente em http://localhost:8000).

Listando objetos com a Class Based View ListView

Já para listar registros de uma tabela do Banco de Dados, podemos utilizar a ListView (documentação).

Aqui, vamos utilizar a entidade Funcionario do nosso projeto HelloWorld.

Nela, nós configuramos o Model que deve ser buscado (Funcionario no nosso caso), e ela automaticamente faz a busca por todos os registros presentes no banco de dados da entidade informada.

Então, a View ficará da seguinte forma:

1
2
3
4
5
6
7
from django.views.generic.list import ListView
from helloworld.models import Funcionario

class FuncionarioListView(ListView):
  template_name = "lista.html"
  model = Funcionario
  context_object_name = "funcionarios"

Essa View vai expor o objeto declarado em context_object_name no template para iteração.

Já a configuração de rotas:

1
2
3
4
5
6
from django.urls import path
from helloworld.views import FuncionarioListView

urlpatterns = [
    path('funcionarios/', FuncionarioListView.as_view()),
]

E o template HTML pode iterar sobre a variável funcionarios da seguinte forma, criando uma Tabela HTML com uma linha por Funcionário:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang="pt-br">
<head>
    <meta charset="UTF-8">
    <title>Primeira Template</title>
</head>
<body>
    <h1>Esse template será renderizado pelo Django</h1>

    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Nome</th>
                <th>Sobrenome</th>
                <th>Remuneração</th>
            </tr>
        </thead>
        <tbody>
            {% for funcionario in funcionarios %} 
                <tr>
                    <td>{{ funcionario.id }}</td>
                    <td>{{ funcionario.nome }}</td>
                    <td>{{ funcionario.sobrenome }}</td>
                    <td>R$ {{ funcionario.remuneracao }}</td>                    
                </tr>
            {% endfor %}
        </tbody>
    </table>
</body>
</html>

E o resultado é uma página lista.html contendo a lista de todos os funcionários cadastrados.

Dica: Eu geralmente coloco o nome da View como sendo o Model com a CBV base. Por exemplo: se eu fosse criar uma view para listar todos os Cursos cadastrados, eu daria o nome de: Model=”Curso” + CBV=”ListView” = CursoListView.

Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine a PyDicas e receba 30 dias do melhor conteúdo Python direto na sua Caixa de Entrada: direto e sem enrolação!

Atualizando objetos com a Class Based View UpdateView

Para atualizar registros de uma tabela do Banco de Dados, utilizamos a UpdateView do Django (documentação)

Com ela, configuramos qual o Model, os campos que estarão disponíveis para atualização e qual o nome do template, dessa forma.

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.views.generic.edit import UpdateView
from helloworld.models import Funcionario

class FuncionarioUpdateView(UpdateView):
    template_name = "atualiza.html"
    model = Funcionario
    fields = [
      'nome',
      'sobrenome' ,
      'cpf',
      'tempo_de_servico',
      'remuneracao'
    ]

Dica! Ao invés de todos os campos em fields em formato de lista de strings, podemos utilizar fields = '__all__' que o Django irá buscar todos os campos para você!

:thinking: Mas… E de onde o Django vai pegar o id do objeto a ser buscado?

O Django precisa ser informado do id ou slug para poder buscar o objeto correto a ser atualizado.

Podemos fazer isso de duas formas:

Primeiro, na configuração de rotas (urls.py).

1
2
3
4
5
6
7
8
9
10
from django.urls import path
from helloworld.views import FuncionarioUpdateView

urlpatterns = [
    # Utilizando o {id} para buscar o objeto
    path('funcionario/<id>', FuncionarioUpdateView.as_view()),

    # Utilizando o {slug} para buscar o objeto
    path('funcionario/<slug>', FuncionarioUpdateView.as_view()),
]

:thinking: Mas o que é slug?

Slug é uma forma de gerar URLs mais legíveis a partir de dados já existentes.

Exemplo: podemos criar um campo slug utilizando o campo nome do funcionário. Dessa forma, as URLs ficariam assim:

:point_right: /funcionario/vinicius-ramos

e não assim (utilizando o id na URL):

:point_right: /funcionario/175

No campo slug, todos os caracteres são transformados em minúsculos e os espaços são transformados em hífens.

A segunda forma de buscar o objeto que estará disponível na tela de atualização é utilizando (ou sobrescrevendo) o método get_object() da classe pai UpdateView.

A documentação desse método traz (traduzido):

“Retorna o objeto que a View irá mostrar. Requer self.queryset e um argumento pkou slugno URLConf. Subclasses podem sobrescrever esse método e retornar qualquer objeto.”

Ou seja, o Django nos dá total liberdade de utilizarmos a convenção (parâmetros passados pela URLConf) ou a configuração (sobrescrevendo o método get_object()).

Basicamente, o método get_object() deve pegar o id ou slug da url e realizar a busca no banco de dados até encontrar aquele id:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from django.views.generic.edit import UpdateView
from helloworld.models import Funcionario

class FuncionarioUpdateView(UpdateView):
    template_name = "atualiza.html"
    model = Funcionario
    fields = '__all__'
    context_object_name = 'funcionario'

    def get_object(self, queryset=None):
      funcionario = None

      # Se você utilizar o debug, verá que os 
      # campos {pk} e {slug} estão presente em self.kwargs
      id = self.kwargs.get(self.pk_url_kwarg)
      slug = self.kwargs.get(self.slug_url_kwarg)

      if id is not None:
        # Busca o funcionario apartir do id
        funcionario = Funcionario.objects.filter(id=id).first()

      elif slug is not None:        
        # Pega o campo slug do Model
        campo_slug = self.get_slug_field()

        # Busca o funcionario apartir do slug
        funcionario = Funcionario.objects.filter(**{campo_slug: slug}).first()

      # Retorna o objeto encontrado
      return funcionario

Dessa forma, os dados do funcionário de id ou slug igual ao que foi passado na URL estarão disponíveis para visualização no template atualiza.htmlutilizando o objeto funcionario!

No caso geral, eu prefiro utilizar a convenção (configuração no URLConf).

:wave: Ei, você aí! Quer se sentir realmente capaz ao desenvolver Aplicações Web com Django? Então clique no link abaixo e dê o próximo passo agora mesmo!

Jornada Django

A Jornada Django foi pensada em quem já sabe Python e quer dar o próximo passo. Aqui você vai dominar o Desenvolvimento Web com o poderoso Django.

Vinícius Ramos
Vinícius Ramos 🇺🇸 Senior Software Engineer 🇧🇷 Fundador
Conhecer detalhes
Check
Suporte a dúvidas
Check
Certificado de Conclusão
Check
Comunidade de Alunos
Check
Cursos gratuitos de HTML
Check
Cursos gratuitos de CSS
Check
Cursos gratuitos de Javascript

Deletando objetos com a Class Based View DeleteView

Para deletar funcionários, utilizaremos a DeleteView (documentação).

Sua configuração é similar à UpdateView: nós devemos informar via URLConf ou get_object() qual o objeto que queremos excluir.

Precisamos configurar:

  • O template que será renderizado.
  • O model associado à essa view.
  • O nome do objeto que estará disponível no template (para confirmar ao usuário, por exemplo, o nome do funcionário que será excluído).
  • A URL de retorno, caso haja sucesso na deleção do Funcionário.

Com isso, a view pode ser codificada da seguinte forma:

1
2
3
4
5
class FuncionarioDeleteView(DeleteView):
  template_name = "exclui.html"
  model = Funcionario
  context_object_name = 'funcionario'
  success_url = reverse_lazy("website:lista_funcionarios")

Assim como na UpdateView, fazemos a configuração do id para ser buscado no URLConf, da seguinte forma:

1
2
3
urlpatterns = [
    path('funcionario/excluir/<pk>', FuncionarioDeleteView.as_view()),
]

Assim, precisamos apenas fazer um template de confirmação da exclusão do funcionário.

Podemos fazer da seguinte forma:

1
2
3
4
5
6
7
8
9
10
<form method="post">
    {% csrf_token %}

    Você tem certeza que quer excluir o funcionário <b>{{ funcionario.nome }}</b>? <br><br>

    <button type="button">
        <a href="{% url 'lista_funcionarios' %}">Cancelar</a>
    </button>
    <button>Excluir</button>
</form>

Algumas observações:

  • Lembra do atributo context_object_name? Olha ele presente lá na quarta linha!
  • A tag do Django {% csrf_token %} é obrigatório em todos os forms pois está relacionado à proteção que o Django provê ao CSRF - Cross Site Request Forgery (tipo de ataque malicioso - saiba mais aqui).
  • Não se preocupe com a sintaxe do template! Veremos mais sobre ele em outro post!!!

Criando objetos com a Class Based View CreateView

A View para criação de novos registros em nosso banco de dados é bem simples!

Aqui precisamos apenas mostrar para o Django o model, dizer o nome do template, a classe do Formulário e a URL de retorno - caso haja sucesso na inclusão do Funcionário.

Podemos fazer isso da seguinte forma:

1
2
3
4
5
6
7
8
9
10
from helloworld.models import Funcionario
from helloworld.forms import InsereFuncionarioForm
from django.views.generic import CreateView
from django.urls import reverse_lazy

class FuncionarioCreateView(CreateView):
  template_name = "cria.html"
  model = Funcionario
  form_class = InsereFuncionarioForm
  success_url = reverse_lazy("website:lista_funcionarios")

A função reverse_lazy() traduz a View em URL.

No nosso caso, queremos que quando haja a inclusão do Funcionário, sejamos redirecionados para a página de listagem, para podermos conferir que o Funcionário foi realmente adicionado.

E a configuração da rota no arquivo urls.py fica assim:

1
2
3
4
5
6
from django.urls import path
from helloworld.views import FuncionarioCreateView

urlpatterns = [
    path('funcionario/cadastrar/', FuncionarioCreateView.as_view()),
]

Com isso, estará disponível no template configurado (cria.html, no nosso caso), um objeto form contendo o formulário para criação do novo funcionário.

Podemos mostrar o formulário de duas formas.

A primeira mostra o formulário inteiro sem formatação e da forma como o Django nos entrega.

Podemos mostrá-lo no nosso template da seguinte forma:

1
2
3
4
5
6
7
<form method="post">
  {% csrf_token %}

  {{ form }}

  <button type="submit">Cadastrar</button>
</form>

Uma observação: apesar de ser um Form, sua renderização não contém as tags <form></form> - cabendo a nós incluí-los no template.

Já a segunda, é mais trabalhosa, pois temos de renderizar campo a campo no template. Porém, nos dá um nível maior de customização.

Podemos renderizar cada campo do form dessa forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<form method="post">
  {% csrf_token %}

  <label for="{{ form.nome.id_for_label }}">Nome</label>
  {{ form.nome }}

  <label for="{{ form.sobrenome.id_for_label }}">Sobrenome</label>
  {{ form.sobrenome }}

  <label for="{{ form.cpf.id_for_label }}">CPF</label>
  {{ form.cpf }}

  <label for="{{ form.tempo_de_servico.id_for_label }}">Tempo de Serviço</label>
  {{ form.tempo_de_servico }}

  <label for="{{ form.remuneracao.id_for_label }}">Remuneração</label>
  {{ form.remuneracao }}

  <button type="submit">Cadastrar</button>
</form>

E assim, temos:

  • {{ form.campo.id_for_label }} traz o id da tag <input ...> para adicionar à tag <label></label>.
  • Utilizamos o {{ form.campo }} para renderizar um campo do formulário, e não ele inteiro.

Conclusão

É isso galera! :wave:

Chegamos ao final de mais um post em nosso Blog!

Você aprendeu sobre as Class Based Views (ou CBV) para tratar as requisições no Django e como utilizar as principais Views que o Django nos fornece.

Fique por dentro que ainda tem muito mais conteúdos para vocês!!!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.