Login Required Mixin - Django class-based generic views - IV

Vamos ver como trabalhar com as CBV + o decorator login_required de forma reaproveitável, através de um Mixin

Introdução

# Se quer saber primeiro sobre class based generic views e esta série de artigos que estou fazendo, basta ler este trecho do primeiro artigo da série.

# Se não quiser ler teoria e explicações dos porquês, tudo bem, pode ir diretamente para a solução. (okay face)

Ok, então nossa aplicação precisa ter views que somente podem ser acessadas se o usuário estiver logado. E se estamos utilizando generic views, especialmente class based generic views é um pouco diferente do convencional modo como você provavelmente fazia.

Criando views somente para usuários logados com class based generic views

Vou apresentar uma forma que é bem interessante, você escreverá pouco e será muito, muito fácil reutilizar sempre que precisar. =]

antes você fazia algo assim:

from django.contrib.auth.decorators import login_required

@login_required
def view_que_requer_autenticacao(request):
    context = ...
    return render(request, 'index.html', context)

Toda vez que precisasse você utilizava o decorator login_required.

agora é um pouco diferente...

Como as views são baseadas em classes, que possuem métodos e atributos, você precisa de duas coisas. Uma forma de usar o decorator login_required em um método e saber qual método você deve decorar.

Bem, para decorar um método vamos 'decorar o decorador', ou seja, usaremos o decorador method_decorator no decorador login_required. Isto será feito para decorar o método dispatch de nossa view - ele é responsável por verificar qual método HTTP você está utilizando em sua requisição e executá-lo - (se quiséssemos poderíamos usar o decorator especificamente no método HTTP desejado)  ele existe em nossas class based generic views, então vamos sobrescrevê-lo - e vamos fazer de uma forma reaproveitável, através dos Mixins (exemplo de mixin na documentação do django).

No repositório que estou utilizando para armazenar os exemplos eu decidi criar uma app "core" e em seu arquivo views.py eu criei meu Mixin que será o responsável por aplicar o login_required no dispatch, mas você pode inserir em seu projeto da forma que ficar melhor para você. Dessa forma:

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required

class LoginRequiredMixin(object):
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(LoginRequiredMixin, self).dispatch(*args, **kwargs)

Em meu arquivo de views vou importar essa classe - esse Mixin - que acabei de criar, (no meu caso no arquivo exemplo_login_required.py):

from django.views.generic import TemplateView
from core.views import LoginRequiredMixin

class ViewQueExigeAutenticacao(LoginRequiredMixin, TemplateView):
    template_name = 'template_para_pagina_login_required.html'

Utilizando o recurso de herança múltipla do Python nós adicionamos o Mixin LoginRequiredMixin que criamos em core.views. Lembrando que a ordem importa, para mais informações busque saber de "herança múltipla em python".

Com isto feito teremos o comportamento esperado, se você acessar a view ViewQueExigeAutenticacao e não estiver logado, então será redirecionado para algo como: /accounts/login/?next=/app-exemplo/exemplo-login-required/.

NOTE: isso vai depender do seu settings.LOGIN_URL, por padrão ele tem o valor  '/accounts/login/', sinta-se à vontade para alterar e ver como muda.

Então você cria seu formulário de login que deve estar mapeado de acordo com seu settings.LOGIN_URL e pronto, terá uma view, que se você não estiver logado, será redirecionado para o formulário de login.

Conclusão

Então, sempre que precisar proteger uma view de usuários não-logados, basta herdar o Mixin LoginRequiredMixin em sua view, sempre antes do do possível ListView, DetailView, CreateView, TemplateView, entre outros. Acho que o artigo até ajudou para quem não conhecia essa possibilidade de criar Mixins para as class based generic views do Django.

Leia também:

blog comments powered by Disqus