Django Users
Django nos provee de un modelo y un sistema completo de autenticación de usuarios.  
ESTO NOS VIENDE DE LA PUTA MADRE. Es muy útil e intuitivo, de hecho, quedaras lol.  
La Idea
La idea es hacer un sitio en donde el usuario pueda ver su perfil.
Además, crearemos una forma de agregar comentarios a productos.  
Estaremos usando el proyecto anterior ProyectoDjango.
Si no tienes el proyecto, tienes dos opciones:  
- Puedes ver todos los capítulos anteriores y recrear el proyecto (recomendado)
 
- Descargar 
ProyectoDjango (no recomendado) 
Recuerda
- Crear un entorno virtual de Python.
 
- Activar el entorno virtual de Python.
 
- Instalar Django.
 
Manejo del inicio de sesión, registro y logout
Para esto, crearemos una nueva aplicación, asi mantenemos un orden. La app la llamare autenticacion...
py manage.py startapp autenticacion  
En views.py de la aplicación autenticacion, creare las siguientes vistas:  
 | from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout 
from .forms import SignupForm, LoginForm
from django.contrib.auth.decorators import login_required
# Create your views here.
# 👇 uso de un decorador
@login_required # 👈 se obliga al usuario a tener una sesion activa para ver esta vista
def index(request):
    return render(request, "autenticacion/index.html")
  | 
 
El decorador permite que Django se encargue de las redirecciones en el caso de que un usuario no tenga sesión activa. Si la tiene, simplemente devuelve la vista.  
 | def registrar(request):
    # 👇 si el usuario tiene sesion activa...
    if request.user.is_authenticated:
        return redirect('autenticacion:index') # entonces lo mandamos al inicio de la app
    form = SignupForm(request.POST)
    if request.method == 'POST':
        if form.is_valid():
            form.save()
            return redirect('autenticacion:login')
    return render(request, 'autenticacion/signup.html', {'form': form})
  | 
 
El formulario hereda de otro, por lo que ese "padre" hereda la lógica de registro del usuario.  
Al final entendamos que un Usuario es solo un registro. Y Django se encargará de lo más tedioso.  
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18  | def iniciarsesion(request):
    if request.user.is_authenticated:
        return redirect('autenticacion:index')
    if request.method == 'POST':
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            # 👇 la funcion authenticate nos permite validar un usuario
            user = authenticate(request, username=username, password=password)
            # 👇 si la funcion devuelve un 'Usuario', significa que las credenciales son correctas
            if user:
                # 👇 la funcion login inicia la sesion del usuario
                login(request, user)
                return redirect('autenticacion:index') # lo mandamos al perfil
    else:
        form = LoginForm()
    return render(request, 'autenticacion/login.html', {'form': form})
  | 
 
 | @login_required # 👈 obviamente, un usuario sin sesion no puede terminar una
def cerrarsesion(request):
    logout(request) # cerramos la sesion del usuario
    return redirect('autenticacion:login') # lo mandamos al sitio de inicio de sesion
  | 
 
Debemos crear el archivo forms.py para definir los formularios...
Primero, importamos lo necesario:  
 | from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User # Modelo de Django que contiene a los usuarios
  | 
 
Luego, creamos nuestro formulario de registro:  
 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  | #                👇 nuestro formulario de registro hereda de UserCreationForm, que tiene toda la logica.
class SignupForm(UserCreationForm):
    class Meta:
        model = User
        # 👇 declaramos que campos deseamos mostrar en el formulario.
        fields = ['username', 'email', 'password1', 'password2']
        # username, password1 y password2 SON OBLIGATORIOS.
        # 👇 definimos las clases y tipos de entrada
        widgets = {
            "username": forms.TextInput(
                attrs={
                    "class": "form-control",
                }
            ),
            "email": forms.EmailInput(
                attrs={
                    "class": "form-control"
                }
            ),
            "password1": forms.PasswordInput(
                attrs={
                    "class": "form-control"
                }
            ),
            "password2": forms.PasswordInput(
                attrs={
                    "class": "form-control"
                }
            ),
        }
  | 
 
 | class LoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(attrs={"class": "form-control"}))
    password = forms.CharField(widget=forms.PasswordInput(attrs={"class": "form-control"}))
  | 
 
Definición de rutas
Creamos nuestro archivo urls.py dentro de la app autenticacion y definimos las rutas que usaremos:  
 | from django.urls import path
import autenticacion.views as app
app_name = "autenticacion"
urlpatterns = [
    path('', app.index, name="index"),
    path('signup/', app.registrar, name="signup"),
    path('login/', app.iniciarsesion, name="login"),
    path('logout/', app.cerrarsesion, name="logout"),
]
  | 
 
Recuerda que es importante definir la variable app_name y definir las variables name a cada ruta.  
Creando las templates
Ahora, necesitamos el front-end para poder visualizar nuestro sistema de autenticación.
Para ello, creamos la carpeta autenticacion dentro de templates, tal que:  
- templates/
 
- autenticacion/
- index.html
 
- login.html
 
- signup.html
 
 
Index
La página index actuará como el perfil del usuario, allí se podrá ver información sobre el usuario:  
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21  | {% extends 'base.html' %}
{% block title %}Auth{% endblock %}
{% block content %}
<div class="container">
    <!-- la variable 'user' siempre esta disponible, por defecto es un usuario anonimo -->
    <!-- si no hay sesion activa, sus campos no tendran valores -->
    <h1>Bienvenido, {{ user.username }}!</h1>
    <h5>Te registraste el {{ user.date_joined }}</h5>
    <h5>Actualmente, {% if user.is_staff %}eres parte del staff!{% else %}no eres parte del staff.{% endif %}{% if user.is_superuser %} Y eres un Superusuario 👷♂️{% else %} Comun y corriente.{% endif %}</h5>
    <h5>Tu correo registrado es {{ user.email }}</h5>
    <!-- como puedes observar, es simplemente un modelo mas, y con ello podemos acceder a sus columnas -->
    <hr>
    <!-- desde no se que version de Django, para el Logout es necesario con POST (y no GET) -->
    <form action="{% url 'autenticacion:logout' %}" method="post">
        {% csrf_token %}
        <button class="btn btn-danger" type="submit">Cerrar sesión</button>
    </form>
</div>
{% endblock %}
  | 
 
Login
La template login permite que el usuario inicie una sesión a través del formulario de inicio de sesión.  
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16  | {% extends 'base.html' %}
{% block title %}Log in - Auth{% endblock %}
{% block content %}
<div class="container">
    <h1>Login</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form }}
        <br>
        <button class="btn btn-success" type="submit">Iniciar sesión</button>
        ¿No tienes una cuenta? <a href="{% url 'autenticacion:signup' %}">Registrate aquí</a>.
    </form>
</div>
{% endblock %}
  | 
 
Signup
Igualmente, no tiene mucha ciencia...  
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16  | {% extends 'base.html' %}
{% block title %}Sign up - Auth{% endblock %}
{% block content %}
<div class="container">
    <h1>Signup</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form }}
        <br>
        <button class="btn btn-success" type="submit">Registrarse</button>
        ¿Ya tienes una cuenta? <a href="{% url 'autenticacion:login' %}">Inicia sesión aquí</a>.
    </form>
</div>
{% endblock %}
  | 
 
Integración con la template base.html
Es normal que en el navbar (o barra de navegación) se encuentren los típicos botones para iniciar sesión, registrarse y ver el perfil de un usuario. En este caso, no será la excepción.
Para ello, nos dirigiremos a la template base.html y la mejoraremos.  
Esto se hace en la etiqueta header:  
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18  |                 ...
                </ul>
            </div>
            <div class="text-end">
                <!--  user tiene sus metodos, que podemos usar. El siguiente metodo permite saber si el usuario esta autentificado. si no, entonces mostramos los botones comunes -->
                {% if user.is_authenticated %}
                <!-- si el usuario tiene una sesion activa, esta variable es True -->
                <a href="{% url 'autenticacion:index' %}" class="btn btn-primary">Perfil</a>
                {% else %}
                <!-- si no hay sesion, es usuario anonimo -->
                <a href="{% url 'autenticacion:login' %}" class="btn btn-success">Login</a>
                <a href="{% url 'autenticacion:signup' %}" class="btn btn-warning">Sign-up</a>
                {% endif %}
            </div>
        </div>
    </nav>
</header>
...
  | 
 
Configuración de variables de sesión
Django nos permite indicar las rutas para el control del comportamiento del sistema de usuarios. Estas variables se deben definir en settings.py de nuestro proyecto:  
 | # Login
LOGIN_URL = "autenticacion:login" # Si el usuario topa con una vista que pide inicio de sesion, esta variable le indica donde debe Iniciar sesion
LOGIN_REDIRECT_URL = "autenticacion:index" # Si el usuario inicia sesion (sin redireccion del caso de arriba) lo dirige a la vista index de la app autenticacion
LOGOUT_REDIRECT_URL = "tienda:index" # Si el usuario cierra sesion, lo manda a la vista index de la app tienda
  | 
 
Estas variables indican que debe hacer Django en los casos mencionados.
Finalmente, definimos la ruta principal
Ahora es el turno del archivo urls.py dentro de la carpeta del proyecto (ProyectoDjango/urls.py):  
 | urlpatterns = [
    ...
    #       👇 definimos la nueva ruta para la aplicacion
    path('cuenta/', include("autenticacion.urls", namespace="autenticacion")),
]
  | 
 
Y eso es todo.
Ahora ya tienes usuarios que pueden registrase, iniciar sesión, cerrar sesión, etc. La lógica se la dejamos a Django.
✨ES UNA PUTA MARAVILLA ❤.