如何使用自定义AdminSite类?

2024-03-12

这是实现我自己的最佳方式django.contrib.admin.sites.AdminSite?

实际上我在注册时遇到了问题INSTALLED_APPS in django.contrib.admin.autodiscover。如果我使用我的自定义 AdminSite 类urls.py,管理页面上没有显示任何应用程序。

我用一点技巧解决了这个问题。我写了这个类:

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)

并像这样实现我的自定义 AdminSite:

from wltrweb.hacks.django.admin import AdminSiteRegistryFix
from django.contrib.admin import AdminSite

class MyAdminSite( AdminSite, AdminSiteRegistryFix ):
    # do some magic
    pass        


site = MyAdminSite()

所以我可以用这个site for urls.py.

有人知道更好的方法吗?由于我访问以下划线开头的 var,这只不过是一个 hack。我不喜欢黑客。

Edit:另一种方法是重写django.contrib.admin.autodiscover函数,但在这种情况下我会有多余的代码。


问题

使用派生自的自定义类django.contrib.admin.AdminSite对于项目的管理站点,无需编写自定义注册代码来向新类注册模型。当我将第三方应用程序与它们自己的模型一起使用时,我不想仅因为从这些应用程序中添加或删除模型而编辑自定义注册代码。

解决方案

您必须将使用用于管理站点的默认类创建的实例切换到您自己的实例,使用您自己的类创建before django.contrib.admin's autodiscover函数被调用。我这样做是通过:

  1. 有一个可以执行切换的应用程序。 (我使用名为core为了我自己的目的。)

  2. 两种选择:

    1. Django 1.6 至 1.9:use __init__应用程序的执行切换。在 Django 1.8 中,由于下面引用的 Django 1.9 中的更改,您将收到弃用警告。注意这个方法will也适用于 1.9,因为由下面所示的代码加载的 Django 模块在 1.9 中已更改,因此它们不再加载模型。当我使用这种方法时core/__init__.py文件包含:

      from django.contrib import admin
      from django.contrib.admin import sites
      
      class MyAdminSite(admin.AdminSite):
          pass
      
      mysite = MyAdminSite()
      admin.site = mysite
      sites.site = mysite
      
    2. Django 1.9 及以上版本:使用应用程序配置应用程序的执行切换。从 Django 1.9 开始,发行说明状态 https://docs.djangoproject.com/en/1.9/releases/1.9/#features-removed-in-1-9:

      所有模型都需要在已安装的应用程序内定义或声明显式的 app_label。此外,在加载应用程序之前不可能导入它们。特别是,无法在应用程序的根包中导入模型。

      我更喜欢限制在根级别执行的导入,以避免加载模型的风险。虽然从版本 1.9 开始使用__init__上面的方法将工作,目前尚不清楚 1.10 或更高版本是否会引入会导致问题的更改。

      当我使用这种方法时core/__init__.py sets default_app_config = "core.apps.DefaultAppConfig"我有一个core/apps.py像这样:

      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
      

      虽然可以在 1.7 和 1.8 版本中使用此方法,但在这些版本中使用它有点冒险。请参阅下面的注释。

  3. 放置此应用程序earlier than django.contrib.admin in the INSTALLED_APPS列表。 (这对于 1.7 及更高版本是绝对必要的。在 Django 的早期版本中,它might即使应用程序晚于django.contrib.admin。不过,请参阅下面的注释。)

注意事项和警告

  • 执行切换的应用程序实际上应该是first应用程序在INSTALLED_APPS列表,以尽量减少其他东西抢走其价值的机会site from django.contrib.admin在进行切换之前。如果另一个应用程序在切换完成之前设法获取该值,则该其他应用程序将引用旧站点。热闹肯定会随之而来。

  • 如果两个应用程序尝试安装自己的新默认管理站点类,则上述方法将无法正常工作。这必须根据具体情况进行处理。

  • Django 的未来版本可能会破坏此方法。

  • 对于 1.9 之前的版本,我更喜欢使用__init__使用应用程序配置进行站点切换,因为初始化文档 https://docs.djangoproject.com/en/1.7/ref/applications/表明ready()应用程序配置的方法调用相对较晚。加载应用程序模块的时间和ready()被调用,模型已被加载,在某些情况下,这可能意味着模块已经获取了site from django.contrib.admin before ready叫做。为了最大限度地降低风险,我有应用程序__init__代码做开关。

    我相信版本 1.7 和 1.8 中存在的风险,并且我通过使用避免了__init__尽早进行站点切换在1.9中并不存在。在所有应用程序加载之前,禁止任何人加载模块。所以在做开关ready中列出的第一个应用程序的回调INSTALLED_APPS应该是安全的。我把一个大项目升级到1.9,使用app配置方式,没有任何问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用自定义AdminSite类? 的相关文章

随机推荐