From 5852941136a895f85a1ef16178a85071537e821a Mon Sep 17 00:00:00 2001 From: JKuijperM Date: Thu, 3 Sep 2026 18:00:22 +0200 Subject: [PATCH] Mueve 'expenses' antes que 'django.contrib.admin' en INSTALLED_APPS Sintoma: /accounts/password_change/ renderizaba la pantalla del admin de Django (cabecera "Administracion de Django", breadcrumb "Inicio > Cambio de contrasena") en vez de la plantilla de la app. Causa: con APP_DIRS=True (settings.py) y sin DIRS explicito, Django busca plantillas recorriendo INSTALLED_APPS en orden y usa la PRIMERA coincidencia por ruta relativa. django.contrib.admin trae sus propias registration/password_change_form.html y registration/password_change_done.html. Como 'django.contrib.admin' aparecia antes que 'expenses' en la lista, sus plantillas ganaban siempre a las de nuestra app, que ni siquiera llegaban a evaluarse. Verificado con el shell de Django (get_template(...).origin.name): Antes del cambio: registration/password_change_form.html -> .../django/contrib/admin/templates/registration/password_change_form.html registration/password_change_done.html -> .../django/contrib/admin/templates/registration/password_change_done.html Despues del cambio: registration/password_change_form.html -> .../expenses/templates/registration/password_change_form.html registration/password_change_done.html -> .../expenses/templates/registration/password_change_done.html Esto tambien explica por que el bug de las plantillas rotas (extendian "base.html", que no existe; ver commit anterior) llevaba tanto tiempo sin dar error: al estar sombreadas, esas plantillas nunca se renderizaban, asi que su TemplateDoesNotExist nunca saltaba. Y explica por que el login SI funcionaba pese a la colision de app: el admin publica su login en "admin/login.html", no en "registration/login.html", asi que ahi no habia conflicto. Efecto secundario esperado y comprobado (no es una regresion, pero hay que saberlo): /admin/password_change/, que Django resuelve tambien por la ruta "registration/password_change_form.html" cuando un admin cambia su propia contrasena, ahora renderiza con el layout completo de la app (menu de navegacion, etc.) en vez del look propio del admin. Probado con un superusuario contra /admin/, /admin/login/, /admin/password_change/ y /admin/password_change/done/: los cuatro responden 200 y el formulario funciona (AdminPasswordChangeForm hereda los mismos campos old_password/new_password1/new_password2 de PasswordChangeForm, asi que el parcial generico de campos los pinta sin problema). El resto del admin (listados, cambio de contrasena de otros usuarios, etc.) no usa ninguna plantilla bajo registration/ ni admin/ que la app sobrescriba, asi que no le afecta. No se reordena alfabeticamente esta lista en el futuro sin tener en cuenta esto: hay un comentario en el propio settings.py explicandolo. --- expenses_manager/expenses_manager/settings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/expenses_manager/expenses_manager/settings.py b/expenses_manager/expenses_manager/settings.py index b85bcb2..8561b56 100644 --- a/expenses_manager/expenses_manager/settings.py +++ b/expenses_manager/expenses_manager/settings.py @@ -61,14 +61,19 @@ if not DEBUG: # Application definition +# 'expenses' va antes que 'django.contrib.admin' a proposito: el cargador de +# plantillas por aplicacion recorre esta lista en orden y se queda con la +# primera coincidencia. Si el admin va antes, sus plantillas de registration/ +# sombrean a las nuestras (paso con password_change_form.html y +# password_change_done.html). No reordenar alfabeticamente. INSTALLED_APPS = [ + 'expenses', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'expenses', ] MIDDLEWARE = [