python - theme - ¿Cómo usar la clase AdminSite personalizada?
django makemigrations (3)
¿Cuál es la mejor manera de implementar mi propio django.contrib.admin.sites.AdminSite
?
En realidad me sale un problema con el registro de INSTALLED_APPS
en django.contrib.admin.autodiscover
. Si uso mi clase personalizada de AdminSite en urls.py
, no se mostraron aplicaciones en la página de administración.
He arreglado esto con un pequeño truco. Escribí esta clase:
from django.contrib.admin.sites import site as default_site
class AdminSiteRegistryFix( object ):
''''''
This fix links the ''_registry'' property to the orginal AdminSites
''_registry'' property. This is necessary, because of the character of
the admins ''autodiscover'' function. Otherwise the admin site will say,
that you havn''t permission to edit anything.
''''''
def _registry_getter(self):
return default_site._registry
def _registry_setter(self,value):
default_site._registry = value
_registry = property(_registry_getter, _registry_setter)
E implementa mi AdminSite personalizado de esta manera:
from wltrweb.hacks.django.admin import AdminSiteRegistryFix
from django.contrib.admin import AdminSite
class MyAdminSite( AdminSite, AdminSiteRegistryFix ):
# do some magic
pass
site = MyAdminSite()
Así que puedo usar este site
para urls.py
¿Alguien sabe de una manera mejor? Desde que accedo a una var, comenzando con un guión bajo, no es más que un hack. No me gustan los hacks
Edición: Otra forma sería reescribir la función django.contrib.admin.autodiscover
, pero en este caso tendría un código redundante.
El problema
Usar una clase personalizada derivada de django.contrib.admin.AdminSite
para el sitio de administración de un proyecto, sin tener que escribir un código de registro personalizado para registrar modelos con la nueva clase. Cuando uso aplicaciones de terceros con sus propios modelos, prefiero no tener que editar el código de registro personalizado solo porque los modelos se agregaron o eliminaron de estas aplicaciones.
La solución
django.contrib.admin
cambiar la instancia creada con la clase predeterminada utilizada para el sitio de administración a su propia instancia, creada con su propia clase antes de django.contrib.admin
la función de autodiscover
django.contrib.admin
. Hago esto por:
Tener una aplicación que realice el cambio. (Utilizo mi aplicación específica del proyecto llamada
core
para mis propios propósitos).Dos opciones:
Django 1.6 a 1.9: use
__init__
de la aplicación para realizar el cambio. En Django 1.8, recibirá una advertencia de desaprobación debido al cambio en Django 1.9 citado a continuación. Tenga en cuenta que este método también funcionará con 1.9 porque los módulos de Django cargados por el código que se muestra a continuación se han modificado en 1.9 para que ya no carguen modelos. Cuando uso este método, mi archivocore/__init__.py
contiene:from django.contrib import admin from django.contrib.admin import sites class MyAdminSite(admin.AdminSite): pass mysite = MyAdminSite() admin.site = mysite sites.site = mysite
Django 1.9 y superior: use la configuración de la aplicación de la aplicación para realizar el cambio. A partir de Django 1.9, como indican las notas de la versión :
Todos los modelos deben definirse dentro de una aplicación instalada o declarar una app_label explícita. Además, no es posible importarlos antes de que se cargue su aplicación. En particular, no es posible importar modelos dentro del paquete raíz de una aplicación.
Prefiero limitar las importaciones que hago en el nivel raíz para evitar el riesgo de cargar modelos. Si bien a partir de la versión 1.9, el método
__init__
anterior funcionará , no se sabe si 1.10 o una versión posterior introducirá un cambio que causará problemas.Cuando uso este método, el
core/__init__.py
establecedefault_app_config = "core.apps.DefaultAppConfig"
y tengo uncore/apps.py
como este:from django.apps import AppConfig class DefaultAppConfig(AppConfig): name = ''core'' def ready(self): from django.contrib import admin from django.contrib.admin import sites class MyAdminSite(admin.AdminSite): pass mysite = MyAdminSite() admin.site = mysite sites.site = mysite
Si bien es posible usar este método con las versiones 1.7 y 1.8, es un poco arriesgado usarlo con esas versiones. Vea las notas a continuación.
Colocar esta aplicación antes que
django.contrib.admin
en la listaINSTALLED_APPS
. (Esto es absolutamente necesario para 1.7 y versiones posteriores. En versiones anteriores de Django, podría funcionar bien incluso si la aplicación es posterior adjango.contrib.admin
. Sin embargo, consulte las notas a continuación).
Notas y advertencias
La aplicación que realiza el cambio debería ser la primera en la lista de
INSTALLED_APPS
para minimizar la posibilidad de que otra cosa tome el valor delsite
dedjango.contrib.admin
antes de que sedjango.contrib.admin
el cambio. Si otra aplicación logra obtener ese valor antes de que se haga el cambio, esa otra aplicación tendrá una referencia al sitio anterior. Seguramente se producirá la hilaridad.El método anterior no funcionará bien si dos aplicaciones intentan instalar su propia nueva clase de sitio de administración predeterminada. Esto tendría que manejarse caso por caso.
Es posible que una futura versión de Django pueda romper este método.
Para la versión anterior a 1.9, preferí usar
__init__
para cambiar de sitio usando la configuración de la aplicación porque la documentación sobre la inicialización indica que el métodoready()
de las configuraciones de la aplicación se llama relativamente tarde. Entre el momento en que se carga el módulo de una aplicación y se llama el tiempoready()
, se han cargado los modelos, y en algunos casos, podría significar que un módulo ha tomado el valor delsite
dedjango.contrib.admin
antes de que se llameready
. Para minimizar el riesgo, tengo el código__init__
la aplicación para hacer el cambio.Creo que el riesgo que existía en la versión 1.7 y 1.8 y que evité al usar
__init__
para realizar el cambio de sitio lo antes posible no existe en 1.9. Todos tienen prohibido cargar módulos antes de que se carguen todas las aplicaciones. Por lo tanto, hacer el cambio en la devolución de llamada de la primera aplicación que aparece enINSTALLED_APPS
debería ser seguro. Actualicé un proyecto grande a 1.9 y utilicé el método de configuración de la aplicación, sin ningún problema.
Cotización desde https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#customizing-the-adminsite-class
Sin embargo, si desea configurar su propio sitio administrativo con comportamiento personalizado, puede subclasificar AdminSite y anular o agregar lo que desee. Luego, simplemente cree una instancia de su subclase AdminSite (de la misma manera que crearía una instancia de cualquier otra clase de Python), y registre sus modelos y subclases ModelAdmin en lugar de usar la predeterminada .
Supongo que ese es el enfoque más explícito, pero también significa que necesita cambiar el código de registro en los archivos admin.py de sus aplicaciones.
Realmente no hay necesidad de usar la detección automática cuando use su propia instancia AdminSite ya que probablemente importará todos los módulos admin.py por aplicación en su módulo myproject.admin.
El supuesto parece ser que, una vez que comience a escribir su sitio de administración personalizado, se volverá más o menos específico del proyecto y sabrá de antemano qué aplicaciones desea incluir.
Entonces, si no quieres trabajar con el truco anterior, solo veo estas dos opciones. Reemplace todas las llamadas de registro a su sitio de administración personalizado o registre los modelos explícitamente en su módulo de administración.
Desde Django 2.1, hay una solución "lista para https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#overriding-the-default-admin-site ": https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#overriding-the-default-admin-site
from django.contrib import admin
class MyAdminSite(admin.AdminSite):
...
El intercambio del sitio de administración personalizado ahora se realiza agregando su propio AdminConfig a las aplicaciones instaladas.
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = ''myproject.admin.MyAdminSite''
INSTALLED_APPS = [
...
''myproject.apps.MyAdminConfig'', # replaces ''django.contrib.admin''
...
]
Tenga en cuenta la diferencia entre AdminConfig y SimpleAdminConfig, donde este último no desencadena admin.autodiscover()
. Actualmente estoy usando esta solución en un proyecto.