10. Autenticación de usuarios
10.1. Plantillas
Por defecto, el cargador de plantillas de Django las busca en una estructura anidada dentro de cada aplicación. Así que una plantilla home.html
de accounts
tendría que estar ubicada en accounts/templates/accounts/home.html
.
Pero el enfoque de carpeta de plantillas a nivel de proyecto es más limpio y se escala mejor, así que se usará éste.
(news) $ mkdir templates
(news) $ mkdir templates/registration
FICHERO: newspaper_project/settings.py
TEMPLATES = [
{
...
'DIRS': [BASE_DIR / 'templates'],
...
}
]
Tras iniciar o cerrar sesión en un sitio se es redirigido inmediatamente a una página subsiguiente. Por tanto, habrá que decirle a Django dónde enviar al usuario en cada caso. Las configuraciones LOGIN_REDIRECT_URL
y LOGOUT_REDIRECT_URL
hacen eso. Se configurará ambos para redirigirlos a la página de inicio, que tendrá el nombre de URL home
.
Recordar que cuando se crean las rutas URL se tiene la opción de añadir un nombre a cada una. Así que cuando se construya la URL de la página de inicio habrá que asegurarse de llamarla
home
.
Añadir estas dos líneas en la parte inferior del archivo settings.py.
FICHERO: newspaper_project/settings.py
# Redirect
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'
Ahora se pueden crear cuatro nuevas plantillas:
(news) $ touch templates/registration/login.html
(news) $ touch templates/registration/signup.html
(news) $ touch templates/base.html
(news) $ touch templates/home.html
Veamos el código HTML para cada archivo.
base.html
será heredada por cada una de las otras plantillas del proyecto. Usando un bloque como {% block content %}
se puede más tarde sobreescribir el contenido sólo en este lugar desde otras plantillas.
FICHERO: templates/base.html
<html lang="es">
<head>
<meta charset="utf-8">
<title>{% block title %}Newspaper App{% endblock title %}</title>
</head>
<body>
<main>
{% block content %}
{% endblock content %}
</main>
</body>
</html>
FICHERO: templates/home.html
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
¡Hola {{ user.username }}!
<p><a href="{% url 'logout' %}">Logout</a></p>
{% else %}
<p>No estás logueado</p>
<a href="{% url 'login' %}">Login</a> |
<a href="{% url 'signup' %}">Registro</a>
{% endif %}
{% endblock content %}
FICHERO: templates/registration/login.html
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endblock content%}
FICHERO: templates/registration/signup.html
{% extends 'base.html' %}
{% block title %}Registro{% endblock %}
{% block content %}
<h2>Registro</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Registrar</button>
</form>
{% endblock content%}
10.2. URLs
En el archivo urls.py
, a nivel de proyecto, se quiere que la plantilla home.html
aparezca como página de inicio. Pero no se quiere construir una app pages
dedicada todavía, así que se puede usar el atajo de importar TemplateView
y establecer el template_name
justo en el patrón url.
A continuación se quiere "incluir" tanto la app accounts
como la app auth
que incorpora django. La razón es que la app auth
ya proporciona vistas y urls para el inicio y el cierre de sesión. Pero para el registro hay que crear una vista y una url propias.
Para asegurar que las rutas URL sean consistentes se colocarán ambas en accounts/
para que las URLs sean /accounts/login
, /accounts/logout
y /accounts/signup
.
FICHERO: newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include # new
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')), # new
path('accounts/', include('django.contrib.auth.urls')), # new
path('', TemplateView.as_view(template_name='home.html'), name='home'), # new
]
Ahora se crea un archivo urls.py
en la app accounts
.
(news) $ touch accounts/urls.py
Actualizar accounts/urls.py
con el siguiente código:
FICHERO: accounts/urls.py
from django.urls import path
from .views import SignUp
urlpatterns = [
path('signup/', SignUp.as_view(), name='signup'),
]
El último paso es el archivo views.py
que contendrá la lógica del formulario de inscripción. Se usará el CreateView
genérico de Django diciéndole que use CustomUserCreationForm
, para redirigirse a login
una vez que el usuario se registre con éxito, y que la plantilla se llama signup.html
.
FICHERO: accounts/views.py
from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import CustomUserCreationForm
class SignUp(CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'registration/signup.html'
Arrancar el servidor con python manage.py runserver
e ir a la página principal en http://127.0.0.1:8000/. Probar todo y crear un nuevo usuario testuser
.
Recuerda establecer el idioma en el fichero
settings.py
.```python LANGUAGE_CODE = 'es'
TIME_ZONE = 'Europe/Madrid' ```
Como tenemos un nuevo campo age
añadámoslo al template home.html
. Es un campo del modelo de usuario por lo que para mostrarlo sólo tenemos que usar {{ user.age }}
pero comprobando previamente que su contenido no es null
.
FICHERO: templates/home.html
{% extends 'base.html' %}
{% block title %}Home{% endblock title %}
{% block content %}
{% if user.is_authenticated %}
¡Hola {{ user.username }}!
{% if user.age %}
Tienes {{ user.age }} años.
{% endif %}
<p><a href="{% url 'logout' %}">Logout</a></p>
{% else %}
<p>No has iniciado sesión</p>
<a href="{% url 'login' %}">Login</a> |
<a href="{% url 'signup' %}">Registro</a>
{% endif %}
{% endblock content %}
10.3. Admin
Entrar también en el administrador para ver las dos cuentas de usuario. No se podrá entrar con una cuenta que no sea de superusuario.
Todo está funcionando pero no hay un campo email
para el usuario testuser
porque no fue incluido en accounts/form.py
.
Este es un punto importante: sólo porque el modelo de usuario tenga un campo no implica que se incluirá en nuestro formulario de registro personalizado a menos que se añada explícitamente. Hagámoslo ahora.
En principio accounts/forms.py
tiene el siguiente aspecto:
FICHERO: accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
Como campos se usan Meta.fields
que sólo muestran la configuración por defecto de nombre_de_usuario/contraseña. Pero también se puede establecer explícitamente qué campos se quieren mostrar, así que se actualizará para pedir un nombre_de_usuario/correo_electrónico/contraseña configurándolo como ('username', 'email','age')
. ¡No se necesita incluir el campo password
porque es obligatorio! Pero todos los demás campos pueden ser configurados como se quiera.
FICHERO: accounts/forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('username', 'email', 'age') # new
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email', 'age') # new
El flujo de autenticación de usuarios de Django requiere un poco de configuración, pero puede verse que también proporciona una increíble flexibilidad para configurar el registro e iniciar la sesión exactamente como se requiera.
10.4. Conclusión
Hasta ahora la aplicación Newspaper
tiene un modelo de usuario personalizado y funciona con páginas de registro, login y logout aunque no tiene muy buen aspecto. Próximamente se añadirá Bootstrap para mejorar el estilo además de una app dedicada pages
.
|\/| [- || ~|~ [- ( /\ ~|~ () ^/_ '|