Como implementar django-registration y personalizar sus plantillas

Quienes me conocen en el ámbito laboral, saben lo mucho que me gusta Django 😄

Hace años que muchos de los proyectos personales relacionados con aplicaciones web, los hago acompañados de este framework Python.

En este artículo daré 4 pistas sobre cómo implementar django-registration y poder personalizar las plantillas visuales y las que utiliza para enviar los correos de registro y validación.

El objetivo es tener una aplicación con un sistema de registro de usuarios que tenga todas las funcionalidades básicas cubiertas, y además, personalizadas. Todo está probado con Django 3.0.3 y django-registration 3.1.

No es un artículo que entre en detalle y en el que estén todas las líneas de código necesarias para que esto funcione. Es un pequeño resumen que creo que puede servir para sacar dudas que yo mismo me encontré a lo largo del desarrollo.

Vamos a ver los siguientes pasos.

  • Instalar y configurar django-registration
  • Registro de uno o de dos pasos?
  • Personalizar todas las plantillas y correos
  • Ejemplos de plantillas personalizadas

Instalar y configurar django-registration

No voy a detallar los pasos más fáciles de la instalación porque están mejor explicados en la documentación oficial. En lugar de esto, explicaré qué configuración he preparado yo para uno de mis proyectos, que en más de un caso ha sido fruto de un buen rato de I+D hasta conseguir el funcionamiento que quería.

Tras la instalación via requirements.txt o pip, el siguiente paso es configurarlo a través del fichero settings.py

# Django registration
ACCOUNT_ACTIVATION_DAYS = 7
REGISTRATION_OPEN = True
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = os.path.join(BASE_DIR, 'tmp/email')

En mi caso he configurado 7 días de activación (hasta que caduca el enlace). Las otras 3 líneas las he utilizado en el entorno de desarrollo y personalizado en el fichero settings.py de producción. En este caso me interesa poder abrir o cerrar el registro a nuevos usuarios, y en el entorno de desarrollo desactivar el envío de mails, que en realidad se guardan dentro de un fichero en la carpeta /tmp/email y es mucho más fácil consultarlos de esta forma que montar un servidor de correo interno.

Después hay que configurar las URL’s para decirle a Django qué módulos cargar y bajo qué patrones.

from django.urls import include, path

urlpatterns = [
    ...
    path('accounts/', include('django_registration.backends.activation.urls')),
    path('accounts/', include('django.contrib.auth.urls')),
]

Ya que más adelante explicaré cómo personalizar todas las plantillas y URL’s, hay que tener en cuenta que en caso de querer hacerlo, las líneas anteriores deben ir al final de las que personalicemos.

Registro de uno o de dos pasos?

Hay dos formas de implementar el registro. Con el de un solo paso conseguimos que el usuario esté confirmado y sin necesidad de validar su cuenta de correo.

En cambio, el registro de dos pasos obliga al usuario a validar su dirección de correo. Hay pocas excusas para no usar este segundo método.

La diferencia en la configuración es que, si queréis utilizar el registro de un solo paso, en lugar de importar las URL de backend.activation.urls hay que importar:

path('accounts/', include('django_registration.backends.one_step.urls')),

Personalizar todas las plantillas y correos

Aquí viene lo divertido. En mi caso, que siempre me gusta tenerlo todo bien ordenado en una estructura de carpetas y ficheros lo más coherente posible, he personalizado la localización de todas las plantillas visuales y las que se utilizan para en envío de correos.

1 bf7tPArrqnPog0PEFdCvIA 1

Tengo una aplicación de Django llamada users que centraliza todo lo relacionado con los usuarios de la web.

Dentro de la carpeta /templates/registration tengo todas las relacionadas con el proceso de registro. Plantillas de la aplicación y de los correos. La de login.html dentro de templates pero fuera de registration.

Para que esto funcione, debemos personalizar las URL’s para que carguen las plantillas en estas rutas, que no son las que trae por defecto django-registration.

Registro y correo de activación

Este primer path es para crear la página de registro bajo la URL accounts/register. Aquí cargamos la plantilla registration_form.html y llamamos al RegistrationView pasándole también la ruta de las dos plantillas de correo que se utilizarán para generar el mail de activación.

1 mnNN CsCPnhN7fsDK074mg
path('accounts/register/',
RegistrationView.as_view(
form_class=CustomUserForm,
template_name="registration/registration_form.html",
email_body_template = 'registration/activation_email_body.txt',
email_subject_template = 'registration/activation_email_subject.txt'
),
name='django_registration_register',
),

En el fichero forms.py declaramos la clase CustomUserForm de la siguiente manera:

from django_registration.forms import RegistrationForm
class CustomUserForm(RegistrationForm):
username = forms.Field(
widget=forms.TextInput(
attrs={'placeholder': _('Username')}
)
)
email = forms.Field(
widget=forms.EmailInput(
attrs={'placeholder': _('Email')}
)
)
password1 = forms.Field(
widget=forms.PasswordInput(
attrs={'placeholder': _('Password')}
)
)
password2 = forms.Field(
widget=forms.PasswordInput(
attrs={'placeholder': _('Type your password again')}
)
)
class Meta(RegistrationForm.Meta):
model = get_user_model()
fields = ('username', 'email')

Registro cerrado

La que muestra el mensaje de error a los usuarios que intentan registrarse cuando tenemos el parámetro REGISTRATION_OPEN = False

path('accounts/register/closed/',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'
),

Registro completado

La plantilla que carga una vez el usuario finaliza el proceso de registro, pero todavía no ha activado la cuenta. Aquí podemos indicarle que revise su bandeja de correo para hacer click en el enlace de activación.

path('accounts/register/complete/',
RegistrationView.as_view(
form_class=CustomUserForm,
template_name="registration/registration_complete.html"
),
name="registration_complete",
),

Registro verificado

A diferencia de la anterior, esta es la página que verá el usuario tras hacer click en el enlace de validación.

path('accounts/activate/complete/',
RegistrationView.as_view(
template_name='registration/activation_complete.html'
),
name='django_registration_activation_complete'
),

Reset de contraseña

Que no se os olvide añadir la opción para que los usuarios puedan resetear su contraseña.

De esta forma, llamando al PasswordResetView, podemos personalizar el nombre de la plantilla en el template_name. Y además, necesitaremos personalizar la pantalla de resultado:

path('accounts/password/reset/',
auth_views.PasswordResetView.as_view(
template_name='registration/password_reset.html'
),
name='password_reset'
),
path('accounts/password_reset/done/',
auth_views.PasswordResetView.as_view(
template_name='registration/password_reset_done.html'
),
name='password_reset_done'
),

Fallo de validación

Los enlaces de activación tienen un formato concreto. Se genera una clave que se utiliza en la URL para que Django pueda verificar la acción. En caso de fallo, también podemos personalizar la plantilla con el mensaje que verá el usuario:

url(r'^accounts/activate/(?P<activation_key>[-:\w]+)/$',
    ActivationView.as_view(
        template_name = 'registration/activation_failed.html'
    ),
    name='django_registration_activate'
),

Ejemplos de plantillas personalizadas

Para terminar, os adjunto un par de plantillas de ejemplo personalizadas que he utilizado en uno de mis proyectos. Concretamente, la aplicación web StoryDevil