使用自定义管理站点自动注册 Django 身份验证模型

Auto register Django auth models using custom admin site

我使用 Django auth 和默认管理站点实现了身份验证管理,但后来我想使用我自己的 AdminSite 来重写一些行为:

class OptiAdmin(admin.AdminSite):
    site_title = "Optimizer site's admin"
    #...Other stuff here

然后注册自己的模型:

admin_site = OptiAdmin(name='opti_admin')
admin.site.register(MyModel, MyModelAdmin)
#Other stuff here

但是当我进入管理站点时,我只能看到我刚刚注册的模型,这对我来说听起来很公平,但我想在这个新的自定义站点中看到所有其他应用程序模型,包括授权用户和组,我不知道如何像默认管理员那样自动执行此操作,请帮助:)。

Django 文档建议将 SimpleAdminConfig 与自定义管理站点一起使用。

INSTALLED_APPS = (
    ...
    'django.contrib.admin.apps.SimpleAdminConfig',
    ...
)

这会阻止使用默认值 AdminSite 注册模型。

文档似乎假设您将单独导入模型并将它们添加到您的自定义管理站点:

from django.contrib.auth.models import Group, User
from django.contrib.auth.admin import GroupAdmin, UserAdmin

admin_site.register(Group, GroupAdmin)
admin_site.register(User, UserAdmin)

如果您在许多应用程序中都有模型,这将是非常重复的。它不提供任何建议如何自动将所有应用程序的模型注册到您的自定义站点。

您可以尝试猴子补丁 admin,然后用您自己的补丁替换 admin.site

from django.contrib import admin
admin.site = OptiAdmin(name='opti_admin')

然后,当代码调用 admin.site.register() 时,它会将模型注册到您的管理站点。在注册任何模型之前,此代码必须 运行。您可以尝试将它放在您应用的 AppConfig 中,并确保您的应用高于 django.contrib.admin.

  1. 使用简单的 __init__() 覆盖创建您自己的 AdminSite。
  2. urls.py.
  3. 中导入 你的 管理员

替换 Django Admin 并获得 autodiscover() 行为是可能的,只需很少的努力。这是以典型 django-admin startproject project 方式生成的项目结构:

project/
    manage.py
    project/
        __init__.py
        settings.py
        urls.py
        wsgi.py
        admin.py  # CREATE THIS FILE

project/admin.py:(我认为在项目级别这样做最有意义。)

from django.contrib.admin import *  # PART 1

class MyAdminSite(AdminSite):
    site_header = "My Site"

    def __init__(self, *args, **kwargs):
        super(MyAdminSite, self).__init__(*args, **kwargs)
        self._registry.update(site._registry)  # PART 2

site = MyAdminSite()

project/urls.py(片段):

from . import admin  # PART 3

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

第 1 部分很简单 Python。通过将 django.contrib.admin 中的所有内容导入您的命名空间,它充当了 drop-in 的替代品。我想你不必这样做,但它有助于保持期望。第 3 部分,只需连接您的管理员即可。第 2 部分是真正的技巧。如documentation says, autodiscover() is called to do the work. All autodiscover does is go through INSTALLED_APPS attempting to import a file called admin.py. Importing runs the code of course and that code is doing the same thing you do to register models (example by decorator and example by method)。没有魔法。您不必 向自定义管理员注册您的模型(如文档所述)。

Autodiscover 看起来比使用装饰器的 register_to kwarg. That indicates you could call autodiscover() yourself passing your own admin. Nope; there's no wiring connected there (future feature?). The assignment happens here and is fixed to the native AdminSite instance here (or here 更聪明)。 Django contrib 模型注册到该实例,任何 third-party 库也将注册到该实例。这不是你可以挂钩的东西。

这里有诀窍,_registry 只是一个字典映射。让 Django 自动发现所有东西,然后 复制映射 。这就是 self._registry.update(site._registry) 起作用的原因。 "self" 是您自定义的 AdminSite 实例,"site" 是 Django 的实例,您可以使用其中任何一个注册您的模型。

(最后说明:如果缺少模型,那是因为导入顺序。所有到 Django 的 AdminSite 的注册都需要在您复制 _registry 之前进行。直接注册到您的自定义管理员可能是最简单的事情。 )

加入 JCotton 的精彩回答:

使用 django 2.0,覆盖自定义管理站点中的 site_headersite_title 仅适用于 index 页面。

要使其适用于所有管理视图,请使用以下内容扩展 JCotton 的代码:

    def __init__(self, *args, **kwargs):
        super(MyAdminSite, self).__init__(*args, **kwargs)
        self._registry.update(site._registry)  # PART 2

        for model, model_admin in self._registry.items():
            model_admin.admin_site = self

只需像这样在您的 CustomAdminSite class 中包含 init 方法。

    class CustomAdminSite(admin.AdminSite):
        def __init__(self, *args, **kwargs):
            super(CustomAdminSite, self).__init__(*args, **kwargs)
            self._registry.update(admin.site._registry)