31

Creando registro de usuario e inicio de sesión con Django

Kevin
iKenshu
113967

Una de las cosas que siempre vamos a necesitar en la mayoría de aplicaciones es un registro de usuarios con su respectivo inicio de sesión. En este tutorial voy a tratar de enseñarles a realizar eso con las vistas basadas en clases o Class Based-Views que ahora trae varias que nos facilitan mucho más esta tarea.

Empecemos con lo básico y voy a suponer que tienes instalado Python, pip, virtualenv y ya sabes como crear un entorno virtual para instalar django en dicho entorno.

Creamos nuestro proyecto:

python django-admin startproject usuarios o django-admin startproject usuarios

Nos movemos a la carpeta del proyecto y aplicamos migraciones.

manage.py migrate o en linux ./manage.py migrate

En este punto deberías tener tus carpetas algo así

├── db.sqlite3
├── manage.py
└── usuarios
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-35.pyc
    │   ├── settings.cpython-35.pyc
    │   ├── urls.cpython-35.pyc
    │   └── wsgi.cpython-35.pyc
    ├── settings.py
    ├── urls.py
    └── wsgi.py

Ahora si corremos nuestro servidor con ./manage.py runserver debería funcionar y veremos un mensaje como este si vamos a localhost:8000 o 127.0.0.1:8000

Ahora vamos a crear nuestra app, donde manejaremos todo lo necesario para nuestro registro e inicio de sesión. Asi que ahora hacemos django-admin startapp perfiles porque extenderemos del modelo User(usuario) que trae Django.

Tendremos cosas nuevas en nuestra carpeta

├── perfiles
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py

Instalamos la app en nuestro settings.py

INSTALLED_APPS = [...'perfiles',
]

Vamos a nuestro models.py y creamos uno llamado Perfil y extendemos del modelo usuario que trae Django el cual ya contiene Username, Nombre, Apellido, Email, Contraseña

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver


classPerfil(models.Model):
    usuario = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.CharField(max_length=255, blank=True)
    web = models.URLField(blank=True)

    # Python 3def__str__(self):return self.usuario.username

@receiver(post_save, sender=User)defcrear_usuario_perfil(sender, instance, created, **kwargs):if created:
        Perfil.objects.create(usuario=instance)

@receiver(post_save, sender=User)defguardar_usuario_perfil(sender, instance, **kwargs):
    instance.perfil.save()

En las últimas dos funciones hacemos uso de los signals específicamente del post_save que lo que hace es crear el perfil después que un usuario es registrado, con esto aseguramos que el usuario tenga perfil. Puedes leer un poco mas sobre esta magia de django en la documentación

Guardamos y corremos las migraciones ./manage.py makemigrations

Migrations for'perfiles':
  perfiles/migrations/0001_initial.py
    - Create model Perfil

Luego ./manage.py migrate

Runningmigrations:
  Applyingperfiles.0001_initial... OK

En este momento podemos crear nuestra url para el index o home que usaremos para que la pagina muestre el username del usuario autenticado y si no, pueda registrarse o iniciar sesión, así que en nuestro archivo urls.py situado dentro de la carpeta usuarios importamos nuestras vistas(las cuales vamos a crear en un momento) y colocamos nuestra linea, el archivo quedara así:

...

from perfiles.views import SignUpView, BienvenidaView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', BienvenidaView.as_view(), name='bienvenida'),
    url(r'^registrate/$', SignUpView.as_view(), name='sign_up'),
]


Ahora dentro de nuestra carpeta perfiles vamos a crear un archivo llamado forms.py donde tendremos el formulario que necesitaremos para que los usuarios se registren, podemos usar el UserCreationForm que trae Django por defecto y tendremos los campos de username, contraseña y la confirmación de esta, pero quería también mostrarle como podemos extender ese formulario con los campos que tenemos en el modelo de User de django, así que tendremos first_name, last_name y email.

Nuestro archivo forms.py queda así

from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth.models import User

from .models import Perfil

classSignUpForm(UserCreationForm):
    first_name = forms.CharField(max_length=140, required=True)
    last_name = forms.CharField(max_length=140, required=False)
    email = forms.EmailField(required=True)

    classMeta:
        model = User
        fields = (
            'username',
            'email',
            'first_name',
            'last_name',
            'password1',
            'password2',
        )

En nuestro views.py vamos a hacer uso de las vistas basadas en clase, por ahora vamos a usar CreateView y TemplateView para mostrar lo que queremos en el index.

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate

from django.views.generic import CreateView, TemplateView

from .models import Perfil

from .forms import SignUpForm


classSignUpView(CreateView):
    model = Perfil
    form_class = SignUpForm

    defform_valid(self, form):'''
        En este parte, si el formulario es valido guardamos lo que se obtiene de él y usamos authenticate para que el usuario incie sesión luego de haberse registrado y lo redirigimos al index
        '''
        form.save()
        usuario = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password1')
        usuario = authenticate(username=usuario, password=password)
        login(self.request, usuario)
        return redirect('/')

classBienvenidaView(TemplateView):
   template_name = 'perfiles/bienvenida.html'

Con el CreateView django automáticamente buscará por todo el proyecto la carpeta templates un archivo llamado app_form o en este caso perfil_form.html el cual podríamos hacer uso en caso de que necesitemos crear una parte de edición donde los usuarios puedan actualizar su perfil. Vamos a crear esa carpeta dentro de perfiles al mismo nivel de nuestro modelos, vistas y demás.

├── manage.py
├── perfiles
│   ├── ...
│   ├── __init__.py
│   ├── migrations
│   │   ├── ...
│   ├── models.py
│   ├── __pycache__
│   │   ├── ...
│   ├── templates
│   │   ├── base.html
│   │   └── perfiles
│   │       ├── bienvenida.html
│   │       └── perfil_form.html

Ahora creamos un base.html:

<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>{% block title %}{% endblock %}</title></head><body>{% block content %}{% endblock content %}</body></html>

Como vemos, dentro de la carpeta templates creamos otra carpeta con el nombre de nuestra app en este caso perfiles y allí ponemos lo que django esta buscando con el mismo nombre. Podemos cambiar el nombre del template colocando template_name como esta reflejado en la vista de bienvenida.

bienvenida.html:

{% extends "base.html" %}{% block title %}Bievenido{% endblock %}{% block content %}{% if user.is_authenticated %}<h1>Hola {{ user.username }}</h1>{% else %}<ahref="{% url 'sign_up' %}">Registrate</a>{% endif %}{% endblock content %}

En el block title lo que hacemos es cambiar el título de nuestro pestaña y eso lo podemos hacer con cada vista que queramos, así no tenemos que escribir nuevamente la etiqueta

En el block content colocamos lo que queremos que se muestra en nuestra pagina y hacemos una condicional donde si el usuario inicio sesión correctamente mostrara su nombre de usuario y un enlace para que pueda cerrar sesión(lo cual no hemos hecho todavía). Si es un visitante, un desconocido, haremos que le muestra el enlace para que pueda registrarse e iniciar sesión(que tampoco hemos hecho, pero hagamoslo de una vez) y el template del formulario es algo parecido:

perfil_form.html

{% extends "base.html" %}{% block title %}Registrate{% endblock %}{% block content %}<formaction=""method="POST">{% csrf_token %}{{ form.as_p }}<inputtype="submit"name="submit"></form>{% endblock content %}

Todos los campos que tenemos en el forms.py los coloca como etiquetas <p></p>(as_p) también podemos colocarlos dentro de listas (as_ul) o como tabla(as_table) podemos renderizar el formulario de muchas maneras en el caso de que queramos darle algo de estilos, pero por ahora nos podemos saltar eso.

Vamos a hacer uso de LoginView, nuevo en Django 1.11, que utiliza el AuthenticationForm que ya hace ciertas validaciones por nosotros, por defecto busca un template en registration/login.html pero vamos a cambiar eso para colocarlo en el mismo sitio de nuestros otros templates. Otra cosa que hace por defecto es que nos redirige al usuario luego de validado el formulario a /accounts/profile/ tampoco queremos eso, queremos que vaya al index para que muestre el nombre del usuario registrado.

Lo único que incluiremos en nuestro views.py es esto:

from django.contrib.auth.views import LoginView

classSignInView(LoginView):
    template_name = 'perfiles/iniciar_sesion.html'

Y ese template lo tendremos así:

{% extends "base.html" %}{% block title %}Inicia Sesión{% endblock %}{% block content %}<formmethod="POST">{% csrf_token %}{{ form.as_p }}<inputtype="submit"name="submit"></form>{% endblock content %}

Prácticamente igual a nuestro formulario anterior, nada nuevo.

Ahora, para que la vista nos redirija al index después de validado del formulario debemos agregar un par de lineas en nuestro settings.py

LOGIN_URL = '/inicia-sesion/'LOGIN_REDIRECT_URL = '/'

En nuestras urls.py agregamos una nueva linea e agregamos SignInView a las vistas que ya tenemos,

url(r'^incia-sesion/$', SignInView.as_view(), name='sign_in'),

Y en nuestro bienvenida.html agregaremos ya todas las urls que vamos a necesitar, quedara algo así

...
    {% if user.is_authenticated %}<h1>Hola {{ user.username }}</h1><ahref="{% url 'sign_out' %}">Cerrar sesión</a>{% else %}<ahref="{% url 'sign_up' %}">Registrate</a><ahref="{% url 'sign_in' %}">Iniciar sesión</a>{% endif %}
...

Con eso después de iniciar sesión el usuario debe ser redirigido al home o index de nuestra aplicación. Bien, ahora hagamos el cerrar sesión que tenemos ahí. Usaremos también una vista basada en clase que ya viene con django LogoutView que pues, nos cierra sesión y por defecto nos redirige a un html en registration/logged_out.html, como los anteriores, lo podemos cambiar con un template_name para redirigirlo a un template que nos muestre una cara triste despidiendolo o simplemente con un mensaje, pero simplemente vamos a mandarlo al index también.

Si, exacto, vamos al settings.py y agregamos una nueva linea:

LOGOUT_REDIRECT_URL = '/'

Y agregamos la nueva vista en views.py

from django.contrib.auth.views import LoginView, LogoutView 

classSignOutView(LogoutView):pass

No necesitamos pasarle mas nada, solo queremos que nos cierre la sesión. Vamos al urls.py agregamos una nueva.

url(r'^cerrar-sesion/$', SignOutView.as_view(), name='sign_out'),

Si quieren registrar el modelo Perfil en el admin de django editamos nuestro admin.py

from .models import Perfil

@admin.register(Perfil)classPerfilAdmin(admin.ModelAdmin):
    list_display = ('usuario', 'bio', 'web')

Y listo, con eso tendriamos lo necesario para que nuestro usuario pueda registrarse, iniciar y cerrar sesión siempre llevándonos al index. Sé que no usamos mucha parte de los campos que creamos en el modelo, pero puedo hacerlo en otro tutorial si ustedes quieren donde veamos las cosas necesarias para que el usuario vaya a su perfil y pueda editarlo para agregar esos campos o para darle estilos a nuestro formulario, si se dieron cuenta se ve medio feo. Esto mientras esperamos un nuevo curso de Django.

Si hay algún error, sugerencia o algo en particular pueden dejarlo acá abajo en los comentarios, o mandarme un mensaje directo, estoy abierto a todo tipo de feedback.

Escribe tu comentario
+ 2
Ordenar por:
1
5Puntos
un año

Al correr el servidor me genera este errror

en admin py, line 3, in <module>
@admin.register(Perfil)

1
2 años

Hola buenos días, excelente tutorial,
podrías hacer un tutorial sobre como aplicar estilos a los formularios de registro y login?

1
4846Puntos
3 años

Crack, mil gracias. Lo estaba necesitando!

1
4042Puntos
3 años

Muchas gracias, excelente aporte

1
6Puntos
6 años

Perfecto! Bien explicado. Estaría genial qur el user pueda editar su perfil. Y al registrarse envie un e-mail de bienvenida o confirmación. Saludos.

0
358Puntos
3 años

Cuando quiero ingresar al panel de administrador me aparese el siguiente error:
A server error occurred. Please contact the administrator.

Me pueden ayudar?