logo cosasdedevs

Crear un blog con Django. Parte 5: Login

Crear un blog con Django. Parte 5: Login

My Profile
Dic 08, 2019

Ya estamos llegando casi al final de este tutorial, en esta parte nos encargaremos del login y del registro de usuarios. Django nos provee de un sistema de autenticación y autorización bastante sencillo y customizable. 

Antes de nada, si queréis más info a parte de la que mostraré aquí podéis verla en la documentación.

Para empezar debemos añadir en que urls se realizará el login, la redirección al hacerlo y la redirección al hacer logout, para ello abrimos nuestro archivo simple_blog/settings.py y al final de este añadimos las siguientes líneas:

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'

Lo siguiente que haremos será crear el archivo users/url.py y mover las urls de login y de registro que estaban en el archivo simple_blog/urls.py, ahora quedarán así los dos archivos:

simple_blog/urls.py

from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView


urlpatterns = [
    path('admin/', admin.site.urls),
    path(
        route='',
        view=TemplateView.as_view(template_name='posts/index.html'),
        name='index'
    ),
    path(
        route='post/my-post.html',
        view=TemplateView.as_view(template_name='posts/detail.html'),
        name='detail'
    ),
    path(
        route='sobre-mi',
        view=TemplateView.as_view(template_name='about.html'),
        name='about'
    ),
    path('', include(('users.urls', 'users'), namespace='users')),
]

users/url.py

"""Users URLs."""

# Django
from django.urls import path
from django.views.generic import TemplateView
# View
from users import views

urlpatterns = [
    path(
        route='login',
        view=views.LoginView.as_view(),
        name='login'
    ),
    path(
        route='registro',
        view=views.SignupView.as_view(),
        name='register'
    ),
    path(
        route='logout/',
        view=views.LogoutView.as_view(),
        name='logout'
    ),
    path(
        route='registro_completado/',
        view=TemplateView.as_view(template_name='users/registerok.html'),
        name='registerok'
    ),
]

La url a login y registro han sido actualizadas para que ahora apunte al archivo users/views.py y a las clases que les darán la funcionalidad. También hemos creado la ruta para el registro completo que apunta a una plantilla que crearemos ahora y el logout.

Ahora lo que vamos a hacer es crear el formulario de registro, para ello creamos el archivo users/forms.py e introducimos las siguientes líneas de código:

"""User forms."""

# Django
from django import forms

# Models
from django.contrib.auth.models import User
from users.models import Profile


class SignupForm(forms.Form):
    """Sign up form."""

    email = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.EmailInput()
    )
    username = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.TextInput()
    )
    password = forms.CharField(
        max_length=70,
        widget=forms.PasswordInput()
    )
    password_confirmation = forms.CharField(
        max_length=70,
        widget=forms.PasswordInput()
    )


    def clean(self):
        """Verify password confirmation match."""
        data = super().clean()

        password = data['password']
        password_confirmation = data['password_confirmation']

        if password != password_confirmation:
            raise forms.ValidationError('Las contraseñas no coinciden.')

        return data

    def save(self):
        """Create user and profile."""
        data = self.cleaned_data
        data.pop('password_confirmation')

        user = User.objects.create_user(**data)
        profile = Profile(user=user)
        profile.save()

Aquí lo que estamos haciendo es declarar la clase SignupForm que contendrá todos los campos de nuestro formulario, en este caso estamos declarando que todos los campos sean de tipo texto. Con el campo widget declaramos el sub tipo, para el email, será un input mail, username de tipo input text, y para las contraseñas de tipo password.

Después declaramos la función clean que se ejecutará después de enviar el formulario y validará si la contraseña es igual a la constraseña repetida.

Para finalizar creamos la función save que lo que hará será elminar el campo password_confirmation y guardará la información enviada en la tabla User y Profile.

Ahora vamos a encargarnos de la parte de la vista, para ello abrimos el archivo users/views.py y añadimos el siguiente código:

from django.shortcuts import render

from django.views.generic import FormView
from django.urls import reverse, reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import views as auth_views

# Forms
from users.forms import SignupForm


class SignupView(FormView):
    """Users sign up view."""

    template_name = 'users/register.html'
    form_class = SignupForm
    success_url = reverse_lazy('users:registerok')

    def form_valid(self, form):
        """Save form data."""
        form.save()
        return super().form_valid(form)

Para el registro estamos usando una de las vistas genéricas que tiene django, en este caso FormView, si queréis más info acerca de las vistas genéricas podéis verla en su documentación.

En template_name le pasamos la template que vamos a utilizar.
En form_class el formulario que creamos anteriormente.
success_url será la url a la que redireccionará si todo ha ido bien.
Por último utilizamos la función form_valid para guardar el usuario si todo ha salido bien.

Lo que vamos a hacer ahora es modificar la plantilla que creamos para el registro en el tutorial sobre el diseño, para ello abrimos el archivo templates/users/register.html y reemplazamos el código por el siguiente:

{% extends "users/base.html" %}
{% block title %}Simple blog - Registro{% endblock %}
{% block content %}
<form class="form-signin" method="POST">
    {% csrf_token %}
    <h1><a href="#" class="title-link">Simple Blog</a></h1>
    <h1 class="h3 mb-3 font-weight-normal">Registro</h1>
    <label for="id_email" class="sr-only">Email</label>
    <input type="email" name="email" id="id_email" class="form-control" placeholder="Email" required autofocus>
    <label for="id_username" class="sr-only">Nombre de usuario</label>
    <input type="text" name="username" id="id_username" class="form-control" placeholder="Nombre de usuario" required>
    <label for="inputPassword" class="sr-only">Contraseña</label>
    <input type="password" name="password" id="id_password" class="form-control" placeholder="Contraseña" required>
    <label for="inputPassword" class="sr-only">Repetir contraseña</label>
    <input type="password" name="password_confirmation" id="id_password_confirmation" class="form-control" placeholder="Repetir contraseña" required>
    <div class="checkbox mb-3"></div>
    
    <button class="btn btn-lg btn-primary btn-block" type="submit">Registrarse</button>
    {% if form.errors %}
        {% for field in form %}
            {% for error in field.errors %}
                <div class="alert alert-danger">
                    <strong>{{ error|escape }}</strong>
                </div>
            {% endfor %}
        {% endfor %}
        {% for error in form.non_field_errors %}
            <div class="alert alert-danger">
                <strong>{{ error|escape }}</strong>
            </div>
        {% endfor %}
    {% endif %}
    
    <p class="mt-5 mb-3 text-muted">&copy; Simple Blog {% now "Y" %}</p>
    </form>
{% endblock %}

Los cambios que hemos realizado han sido modificar el formulario para que django capture los campos que vamos a enviar, añadir el csrf_token que lo necesitaremos para validar el formulario y si hay errores al crear el usuario se mostrará una alerta. 

Si todo ha salido bien a la hora de crear un usuario lo enviaremos a una plantilla avisando de que el usuario ha sido creado correctamente, para eso creamos el archivo templates/users/registerok.html y añadimos este código:

{% extends "users/base.html" %}
{% block title %}Simple blog - Registro completado{% endblock %}
{% block content %}
<main role="main" class="container">
   <div class="starter-template">
      <h1>Tu usuario ha sido creado con exito</h1>
      <p class="lead">Si la página no es redirigida en 5 segundos pulsa <a href="{% url 'users:login' %}">aquí</a></p>
   </div>
</main>
<script>
   setTimeout(function(){ 
       window.location.replace("{% url 'users:login' %}");
   }, 5000);
</script>
{% endblock %}

Aquí lo que hacemos es mostrar un mensaje y redireccionar a la página de login utilizando {% url 'users:login' %}, esto mira en nuestros archivos urls.py y genera la url en base al namespace y name que añadimos en nuestras urls.

Para acceder al registro entramos en está página http://127.0.0.1:8000/registro y podemos crear un usuario para realizar pruebas posteriormente.

Ahora que ya tenemos la parte del registro vamos a ponernos manos a la obra con la parte del login. Abrimos nuestro archivo users/views.py y al final de este añadimos las siguientes líneas:

class LoginView(auth_views.LoginView):
    """Login view."""
    template_name = 'users/login.html'


class LogoutView(LoginRequiredMixin, auth_views.LogoutView):
    """Logout view."""
    template_name = 'users/logged_out.html'

A la clase LoginView se le asigna una template y toda la lógica se encarga de hacerla Django. En el caso del logout es exactamente igual aunque como en este caso no necesita template se añade una (aunque no exista) y con esto la parte de las vistas estaría lista.

Para finalizar abrimos el archivo templates/users/login.html y modificamos el código existente por el siguiente:

{% extends "users/base.html" %}
{% block content %}
<form method="POST" action="{% url "users:login" %}" class="form-signin">
    {% csrf_token %}
    <h1><a href="#" class="title-link">Simple Blog</a></h1>
    <h1 class="h3 mb-3 font-weight-normal">Login</h1>
    <label for="id_username" class="sr-only">Usuario</label>
    <input type="text" id="id_username" class="form-control" placeholder="Usuario" name="username" required autofocus>
    <label for="id_password" class="sr-only">Contraseña</label>
    <input type="password" id="id_password" class="form-control" placeholder="Contraseña" name="password" required>
    <div class="checkbox mb-3"></div>
    <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
    {% if form.errors %}
        {% for field in form %}
            {% for error in field.errors %}
                <div class="alert alert-danger">
                    <strong>{{ error|escape }}</strong>
                </div>
            {% endfor %}
        {% endfor %}
        {% for error in form.non_field_errors %}
            <div class="alert alert-danger">
                <strong>{{ error|escape }}</strong>
            </div>
        {% endfor %}
    {% endif %}
    <p class="mt-5 mb-3 text-muted">&copy; Simple Blog {% now "Y" %}</p>
    </form>
{% endblock %}

Al igual que en la template del registro añadimos el csrf_token y si hay errores los capturamos.

Conclusiones

Como veis es muy fácil crear un sistema de login con Django, lo único que cambiaría sería la posibilidad de hacer login con el email en vez de con el usuario, si queréis aprender como hacerlo, podéis ver mi tutorial sobre como realizar el login con email en Django. En el siguiente post veremos como como unir todo el proyecto trabajando con las vistas.

548 vistas

Nos tomamos en serio tu privacidad

Utilizamos cookies propias y de terceros para mejorar la experiencia del usuario a través de su navegación. Si pulsas entendido aceptas su uso. Ver política de cookies.

🐍 Sígueme en Twitter

Si te gusta el contenido que subo y no quieres perderte nada, sígueme en Twitter y te avisaré cada vez que cree contenido nuevo 💪
Luego ¡Te sigo!