Saltar al contenido
🐍 Curso de Python
/

Módulo 4 · Lección 30 de 45

El panel de administración

La aplicación que lleva instalada desde la lección 4, las tres banderas que deciden quién entra, y para qué no hay que usarla.

⏱ 14 min de lectura

Desde la lección 4 hay una ruta admin/ en el fichero de rutas y seis aplicaciones en INSTALLED_APPS que nadie ha tocado. Tres de ellas son esto: un panel completo para consultar y editar los datos, generado a partir de los modelos, con su sistema de usuarios y permisos.

Es la pieza que más fama le ha dado a Django, y la que más se malinterpreta. Hay proyectos que la usan de interfaz principal, y eso acaba mal por razones que conviene entender antes de empezar.

Ya está funcionando#

consola
python manage.py createsuperuser

Con eso y el servidor levantado, http://127.0.0.1:8000/admin/ pide una contraseña y entra. No hay nada que configurar, porque ya venía:

agenda/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    # ...
]

Las cuatro hacen falta y cada una tiene su papel. admin es el panel; auth son los usuarios, los grupos y los permisos; sessions es lo que mantiene la sesión iniciada entre peticiones; y contenttypes es un registro de todos los modelos del proyecto, que es lo que permite que los permisos se refieran a cualquier modelo sin conocerlo de antemano.

Salida en pantalla
sin sesión, /admin/  ->  302 /admin/login/?next=/admin/

Fíjate en ese ?next=: el panel recuerda adónde ibas para llevarte allí después de identificarte. Es un detalle que habrá que replicar a mano en la lección 32.

Y está en español, con LANGUAGE_CODE puesto y sin instalar nada.

Registrar los modelos#

Un modelo no sale en el panel hasta que se registra, y eso se hace en un fichero que startapp ya creó:

contactos/admin.py
from django.contrib import admin

from .models import Contacto, Etiqueta, Grupo

admin.site.register(Grupo)
admin.site.register(Etiqueta)


@admin.register(Contacto)
class ContactoAdmin(admin.ModelAdmin):
        pass

Las dos formas son equivalentes. La primera vale cuando no hay nada que configurar; la segunda es la que se acaba usando siempre, porque en cuanto quieras cambiar algo necesitas la clase, y eso es la lección siguiente.

Ahora se entiende una cosa de la lección 15: el __str__ del modelo es lo que se ve en el panel. Un modelo sin __str__ llena las listas de Contacto object (3), y ese es el sitio donde más molesta.

Quién puede entrar#

Tres banderas en el usuario, y confundirlas es lo normal al principio:

BanderaQué significa
is_activeLa cuenta sirve. Desactivarla es la forma de dar de baja sin borrar
is_staffPuede entrar al panel. Nada más
is_superuserTiene todos los permisos, sin comprobar ninguno

La segunda es la que sorprende. Medido con un usuario al que solo se le pone is_staff:

Salida en pantalla
/admin/                      ->  200
¿ve contactos?               ->  False
/admin/contactos/contacto/   ->  403

Entra, y el panel está vacío. is_staff abre la puerta y no da acceso a nada, porque lo que se ve depende de los permisos. Y pedir la dirección a mano tampoco funciona: 403.

Esa separación es buena. Permite tener a alguien con acceso al panel y a un solo modelo.

Los permisos#

Django crea cuatro por cada modelo, sin que nadie los pida:

Salida en pantalla
add_contacto     | Can add contacto
change_contacto  | Can change contacto
delete_contacto  | Can delete contacto
view_contacto    | Can view contacto

Se crean al aplicar las migraciones, y de ahí salen los botones que se ven o no se ven en el panel. Con solo view_contacto:

Salida en pantalla
lista de contactos  ->  200
página de añadir    ->  403
has_perm('contactos.view_contacto')  ->  True
has_perm('contactos.add_contacto')   ->  False

view es el que permite mirar sin tocar, y es más útil de lo que parece: mucha gente de un equipo necesita consultar y no debería poder editar.

Fíjate en el nombre completo que usa has_perm: aplicacion.accion_modelo. Esa cadena es la misma que se usará en los decoradores de la lección 33.

Grupos#

Dar permisos usuario por usuario no escala. Un grupo es un paquete de permisos:

python
grupo = Group.objects.create(name='Editores')
grupo.permissions.add(*Permission.objects.filter(
    codename__in=['add_contacto', 'change_contacto', 'view_contacto']))
usuario.groups.add(grupo)
Salida en pantalla
tras el grupo, add:    True
tras el grupo, delete: False

Los permisos de una persona son los suyos más los de sus grupos. Y todo esto se hace desde el propio panel, en la sección de autenticación, sin escribir código.

La costumbre sana es la misma que en cualquier sistema: los permisos se dan a grupos y las personas se meten en grupos. Dárselos directamente a alguien funciona y a los seis meses nadie sabe por qué esa persona puede hacer eso.

El historial#

Cada cambio hecho desde el panel queda registrado:

Salida en pantalla
admin | Modificar | Trabajo editado | [{"changed": {"fields": ["Nombre"]}}]

Quién, qué, cuándo y qué campos. Se ve en el botón de historial de cada ficha y vive en un modelo, LogEntry, que se puede consultar.

Tiene un límite importante: solo registra lo que pasa por el panel. Un cambio hecho desde una vista, desde el intérprete o desde una orden de gestión no aparece. No es una auditoría, es el historial del panel.