Implementar un sistema clásico de registro, login y logout

Introducción

Este tutorial tiene como objetivo mostrar cómo utilizar las funciones que ofrece Django para registrar y autenticar usuarios utilizando sus apps y formularios internos. No enseñaré a programar funciones extendidas como podrían ser la de cambiar la contraseña o enviar emails de verificación, pues serían funcionalidades para tratar en tutoriales a parte.

Para este experimento vamos a suponer que necesitamos crear una sección privada sólo para usuarios registrados. Esta área exclusiva la manejaremos dentro de una app llamada users que también gestionará los formularios de inicio de sesión y login:

Creando la app de usuarios

python manage.py startapp users

Una vez la tengáis creada no olvidéis activarla en el settings.py.

Creando las vistas

Tendremos básicamente 4 vistas en la aplicación de usuarios:

  • welcome: Manejará la bienvenida al área para miembros y redireccionará a la vista de identificación si el usuario no ha iniciado la sesión.
  • register: Manejará el formulario de registro de usuarios y autenticará al usuario automáticamente al registrarse.
  • login: Manejará el formulario de identificación de usuarios y redireccionará a la portada si las credenciales son correctas.
  • logout: Manejará la acción de cerrar la sesión y redirecciona a la vista de la portada de nuevo.

Podemos crearlas inicialmente con el mínimo contenido:

views.py

from django.shortcuts import render, redirect

def welcome(request):
    return render(request, "users/welcome.html")

def register(request):
    return render(request, "users/register.html")

def login(request):
    return render(request, "users/login.html")

def logout(request):
    # Redireccionamos a la portada
    return redirect('/')

Las URL que las manejarán serán las siguientes:

proyecto/urls.py

from django.contrib import admin
from django.urls import path
from users import views

urlpatterns = [
    path('', views.welcome),
    path('register', views.register),
    path('login', views.login),
    path('logout', views.logout),

    path('admin/', admin.site.urls),
]

Implementando el logout

Vamos a empezar con el logout porque es la acción más sencilla, sólo tenemos que llamar a la función de mismo nombre que encontraremos en el módulo django.contrib.auth. Os sugiero importar la función con otro nombre porque de esa forma podemos usar logout en la función de la vista:

views.py

from django.contrib.auth import logout as do_logout

# ...

def logout(request):
    # Finalizamos la sesión
    do_logout(request)
    # Redireccionamos a la portada
    return redirect('/')

Tan sencillo como esto.

Implementando la portada

A continuación nos centraremos en añadir una validación a la portada que redireccione al usuario al login en caso de no estar autenticado, así protegeremos su contenido:

views.py

def welcome(request):
    # Si estamos identificados devolvemos la portada
    if request.user.is_authenticated:
        return render(request, "users/welcome.html")
    # En otro caso redireccionamos al login
    return redirect('/login')

El contenido de la portada podría ser el siguiente:

welcome.html

<h2>Área para miembros</h2>

<p>
    Bienvenido <b>{{request.user.username}}</b>, 
    esta página es exclusiva para usuarios registrados.
</p>

<hr />
<a href="/logout">Cerrar sesión</a>

Al añadir este código si intentamos acceder a la la raíz del sitio / nos redireccionará al /login que aún no hemos creado. En caso de ver la portada podría ser por tener una sesión activa préviamente desde el panel de administrador, ya que se gestionan con la misma app interna de Django. Si la cerráis desde el enlace inferior os llevará al login.

Implementando el login

El formulario de identificación es la cosa más sencilla del mundo, sólo necesitamos un campo para el nombre del usuario y otro para la contraseña. Podríamos crearlos manualmente pero también podemos usar los built-in forms de Django.

Así que vamos a importar el formulario de autenticación llamado AuthenticationForm y dejaremos que él lo gestione todo, nosotros sólo lo validaremos e iniciaremos la sesión si la información es correcta:

views.py

from django.contrib.auth import authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login as do_login

# ...

def login(request):
    # Creamos el formulario de autenticación vacío
    form = AuthenticationForm()
    if request.method == "POST":
        # Añadimos los datos recibidos al formulario
        form = AuthenticationForm(data=request.POST)
        # Si el formulario es válido...
        if form.is_valid():
            # Recuperamos las credenciales validadas
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']

            # Verificamos las credenciales del usuario
            user = authenticate(username=username, password=password)

            # Si existe un usuario con ese nombre y contraseña
            if user is not None:
                # Hacemos el login manualmente
                do_login(request, user)
                # Y le redireccionamos a la portada
                return redirect('/')

    # Si llegamos al final renderizamos el formulario
    return render(request, "users/login.html", {'form': form})

El template quedaría de la siguiente forma, dejando que sea el propio Django quién renderice el formulario:

login.html

<h2>Iniciar sesión</h2>

<form method="POST">
    {{ form.as_p }}
    {% csrf_token %}
    <button type="submit">Login</button>
</form>

<hr />
<a href="/register">Registrar usuario</a>

Con esto ya tendremos implementada la identificación:

Si no tenéis un usuario os recomiendo crear uno desde la terminal para probarlo, pero recordad antes hacer una migración inicial:

python manage.py migrate
python manage.py createsuperuser

Además lo interesante es que al ser un formulario integrado soporta la traducción dependiendo del idioma que tenemos configurado en Django y también es capaz de detectar los errores e informar si el usuario no es correcto.

Implementando el registro

Y por últimos vamos con la funcionalidad de añadir nuevos usuarios.

Se maneja de forma muy parecida al login, ya que también hay un formulario integrado para manejar esta situación, se trata de UserCreationForm:

views.py

from django.contrib.auth.forms import UserCreationForm

# ...

def register(request):
    # Creamos el formulario de autenticación vacío
    form = UserCreationForm()
    if request.method == "POST":
        # Añadimos los datos recibidos al formulario
        form = UserCreationForm(data=request.POST)
        # Si el formulario es válido...
        if form.is_valid():

            # Creamos la nueva cuenta de usuario
            user = form.save()

            # Si el usuario se crea correctamente 
            if user is not None:
                # Hacemos el login manualmente
                do_login(request, user)
                # Y le redireccionamos a la portada
                return redirect('/')

    # Si llegamos al final renderizamos el formulario
    return render(request, "users/register.html", {'form': form})

El template sería prácticamente un calco del de login:

register.html

<h2>Registrar usuario</h2>

<form method="POST">
    {{ form.as_p }}
    {% csrf_token %}
    <button type="submit">Registrar</button>
</form>

<hr />

<a href="/login">Iniciar sesión</a>

Se verá más o menos así:

Este formulario de registro tiene la peculiaridad de contener mucho texto de ayuda a la hora de crear las cuentas, pero si queremos podemos esconder esa información borrando el atributo help_text de los tres campos del formulario:

views.py

# Si queremos borramos los campos de ayuda
form.fields['username'].help_text = None
form.fields['password1'].help_text = None
form.fields['password2'].help_text = None

# Si llegamos al final renderizamos el formulario
return render(request, "users/register.html", {'form': form})

Así tendríamos un formulario más limpio, aunque conservaremos los mensajes de error si se introduce un nombre de usuario en uso o si las contraseñas no superan la validación mínima:

 

Django 2.2
10/06/2019

Recursos disponibles

attach_file
Código del tutorial