6 minutos
Como Crear Usuarios De Forma Programática (Manual) en Django
Introducción
Una de las ventajas de Django es su panel administrativo, donde (entre otras muchas cosas) puedes crear, modificar o borrar a los usuarios de tu sistema. Si estás manejando grupos de usuarios para restringir el acceso a ciertas áreas de tu aplicación, también desde este panel puedes gestionar los grupos y usuarios que pertenecen a cada uno estos. Tarde o temprano te encuentras en la necesidad de crear varios usuarios al mismo tiempo, por ejemplo, si tu sistema se usará en una escuela será necesario crear las cuentas para los maestros o alumnos, y hacerlo desde el admin uno por uno no solo es tedioso y muy tardado, también es propenso a muchos errores. En estos casos podemos usar la API del ORM de Django para automatizar la creación de los usuarios.
Requerimientos
Para este ejercicio vamos a necesitar dos grupos de usuarios:
- MAESTRO
- ALUMNO
Y un archivo CSV el cual tendrá la información de cada usuario a crear. La estructura de este archivo es la siguiente:
login | nombre | apellidos | grupo | |
---|---|---|---|---|
aramirez | Arturo | Ramírez Tejeda | [email protected] | MAESTRO |
flopez | Francisco | López García | [email protected] | ALUMNO |
Relaciones entre Usuarios, Grupos y Correos
Django utiliza una relación muchos a muchos (many to many) para referenciar a los usuarios y grupos del sistema. En este tipo de relación se dice que un usuario pertenece a muchos grupos y un grupo lo tienen muchos usuarios. Y cada usuario está ligado a un email por medio de una relación uno a muchos, es decir un usuario puede tener varios emails, pero un email solo puede pertenecer a un usuario.
Para crear los usuarios y asignarlos a un grupo vamos a usar los modelos User
,
Group
e EmailAddress
, los cuales los importamos así:
from escuela.users.models import User
from django.contrib.auth.models import Group
from allauth.account.models import EmailAddress
Nota: en mi caso uso el paquete
allauth
, para que los usuarios puedan restablecer sus contraseñas por medio una liga que les llega a su correo, y para las aplicaciones donde los usuarios se pueden registrar por ellos mismos también permite la creación de usuarios por medio del email.
Implementación del código
Obteniendo los grupos
En nuestro caso ya sabemos de antemano los grupos que vamos a usar, por lo que podemos obtenerlos desde un inicio:
maestro = Group.objects.get(name="MAESTRO")
alumno = Group.objects.get(name="ALUMNO")
En este caso estoy obteniendo los grupos por su nombre y no por su id
para
hacerlo más descriptivo.
Abrimos el archivo para obtener los datos
import csv
# definimos unas constantes para referenciar los campos del archivo
LOGIN = 0
NOMBRE = 1
APELLIDOS = 2
EMAIL = 3
GRUPO = 4
with open("datos.csv", "r") as fp:
reader = csv.reader(fp)
for row in reader:
# la creación de los usuarios va aquí
Creación de los usuarios y grupos
El modelo para los usuarios tiene algunos campos requeridos que tenemos que crear junto con la información del archivos CSV, estos son:
- is_superuser. Es un campo booleano, si es verdadero se considera un administrador del sistema.
- is_staff. Otro campo booleano, en caso de ser verdadero el usuario puede iniciar sesión en el panel administrativo.
- is_active. Campo booleano, indica si un usuario es activo o inactivo.
- date_joined. Un campo de tipo
datetime
, el cual indica la fecha de creación del usuario.
En nuestro caso ningún usuario es superuser, pero los maestros sí pertenecen al staff. Todos los usuarios a crear serán activos. Primero tenemos que crear al usuario:
import datetime
hoy = datetime.datetime.today()
usuario = User(
is_superuser=False
is_staff=True if row[GRUPO] == "MAESTRO" else False,
username=row[LOGIN],
first_name=row[NOMBRE],
last_name=row[APELLIDOS],
email=row[EMAIL],
is_active=True,
date_joined=hoy
)
En este punto se ha creado es usuario pero aun no está guardado, pero necesitamos tener la instancia para la creación de la contraseña, la asignación del email y de los grupos.
Contraseñas
Cuando asignamos una contraseña desde el panel administrativo esta es validada
por Django para que cumpla ciertas normas (longitud, complejidad), pero al crear
la contraseña de forma programática podemos saltarnos estas validaciones. Esto
es útil en caso de que nos soliciten igualar el nombre de usuario con la
contraseña (lo cual dicho sea de paso no se debe de hacer). Para asignar una
contraseña tenemos que usar el método set_password()
:
usuario.set_password("abracadabra")
En este caso nos estamos brincando cualquier validación de Django y asignamos el password tal cual lo especificamos. Podemos verificar si un password cumple los lineamientos de python con:
usuario.check_password("abracadabra") # En este caso regresa False
Por último, podemos generar un password aleatorio que cumple las normas de
Django con el método make_random_password()
de la clase BaseUserManager
:
from django.contrib.auth import get_user_model
User = get_user_model()
my_pass = User.objects.make_random_password()
usuario.set_password(my_pass)
Grupos
Como ya explicamos en un inicio, los grupos y usuarios tienen una relación muchos a muchos, y para poder asignar esta relación, tanto el usuario como los grupos tienen que estar creados y guardados, por lo que tenemos que guardar nuestro usuario y asignarle el grupo correspondiente:
usuario.save()
usuario.groups.add(grupo)
Nota: cuando asignamos el grupo estamos usando
groups
, por que internamente el modelo User tiene definida la relación comogroups = models.ManyToManyField(Group)
.
Al usar add(grupo)
se guarda en automático la relación, por lo que no es
necesario hacer un save()
.
Emails
El proceso de registro por email de allauth
es:
- Se crea el usuario con un email (modelo
User
). - Cuando el usuario inicia sesión por primera vez, se le envía un correo a la
dirección registrada con una liga para autorizar su cuenta, y se crea un
registro en el modelo
EmailConfirmation
, el cual indica que se está en espera de la validación por parte del usuario. - Si el usuario valida su correo, se borra el registro de
EmailConfirmation
y se crea un nuevo registro en el modeloEmailAddress
con la dirección confirmada.
En nuestro caso queremos omitir este proceso de validación para que el usuario
(y su email) ya esté confirmado, por lo que solo tenemos que crear los registros
en EmailAddress
:
EmailAddress.objects.create(
email=row[EMAIL],
verified=True,
primary=True,
user=usuario
)
Nota: Para conocer las diferencias al crear una instancia con
MiModelo()
yMiModelo.objects.create()
ve el post Primeros pasos con el ORM de Django.
Juntando todo
from django.contrib.auth.models import Group
from allauth.account.models import EmailAddress
from django.contrib.auth import get_user_model
import datetime
import csv
User = get_user_model()
LOGIN = 0
NOMBRE = 1
APELLIDOS = 2
EMAIL = 3
GRUPO = 4
hoy = datetime.datetime.today()
maestro = Group.objects.get(name="MAESTRO")
alumno = Group.objects.get(name="ALUMNO")
with open("datos.csv", "r") as fp:
reader = csv.reader(fp)
for row in reader:
usuario = User(
is_superuser=False
is_staff=True if row[GRUPO] == "MAESTRO" else False,
username=row[LOGIN],
first_name=row[NOMBRE],
last_name=row[APELLIDOS],
email=row[EMAIL],
is_active=True,
date_joined=hoy
)
passwd = User.objects.make_random_password()
usuario.set_password(passwd)
usuario.save()
# asignamos el grupo
usuario.groups.add(maestro if row[GRUPO] == "MAESTRO" else alumno)
# autorizamos el email
EmailAddress.objects.create(
email=row[EMAIL],
verified=True,
primary=True,
user=usuario
)
Nota: al inicio importaba el modelo
User
confrom escuela.users.models import User
pero aquí uséfrom django.contrib.auth import get_user_model
, esto es por que yo le hice modificaciones a este modelo. Lo dejo así como referencia.
Este script lo podemos ejecutar con el shell
de Django:
python manage.py shell < crear_usuarios.py
Conclusión
Django es un framework bastante completo y en la mayoría de los casos automatiza muchas cosas por nosotros. Sin embargo, nos da todas las herramientas para hacer cosas manuales si es que lo requerimos. El código final se puede mejorar agregando validaciones en el caso de que ya exista un usuario, o el archivo tenga un grupo inválido, pero esto ya se deja como ejercicio para el lector.