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

25

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

我使用Django认证功能默认的管理员站点来管理身份验证,但后来我想使用自己的AdminSite来重新编写一些行为。

(Two possible versions, depending on the level of colloquialism desired)
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

但是当我进入管理员网站时,我只能看到我刚注册的模型,这对我来说听起来很合理,但我希望在这个新的自定义网站中能看到所有其他应用程序的模型,包括认证的用户和组,而我不知道如何像默认管理员一样自动完成此操作,请帮忙 :)

5个回答

24
  1. 通过简单的__init__()覆盖创建自己的AdminSite。
  2. urls.py中导入您自己的管理员。

通过最小的努力,可以替换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()

项目/urls.py(片段):

from . import admin  # PART 3

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

第一部分是简单的Python代码。通过从django.contrib.admin导入所有内容到您的命名空间中,它作为一个可替换组件。我想你不一定要这样做,但它有助于保持期望。第三部分,只需连接您的管理页面。第二部分才是真正的技巧所在。就像文档所说的那样,调用autodiscover()来完成工作。自动发现实际上只是浏览INSTALLED_APPS尝试导入一个叫做admin.py的文件而已。导入当然会运行代码,而这些代码正在做与您注册模型相同的事情(例如使用装饰器方法示例)。没有什么魔法。您不必将您的模型与您自定义的管理页面注册(如文档所述)。

autodiscover()看起来比它聪明,因为它有一个register_to kwarg。这表明您可以自己调用autodiscover()并传递自己的管理页面。不,那里没有任何连接线(未来功能?)。赋值发生在这里,并且固定为原生AdminSite实例这里(或使用装饰器时这里)。Django contrib模型注册到该实例,因此也将注册第三方库。您无法挂钩到这个功能。

这里的技巧是,_registry只是一个字典映射。让Django自动发现所有内容,然后只需复制映射。这就是为什么self._registry.update(site._registry)有效。 "self"是您的自定义AdminSite实例,"site"是Django的实例,您可以使用其中任何一个注册您的模型。

(最后注意:如果模型丢失,那是因为导入顺序问题。所有注册到Django的AdminSite需要在您复制_registry之前完成。直接注册到您自定义的管理页面可能是最简单的方法。)


我刚刚尝试了使用Django 1.11和自定义的AdminSite实例。注册的模型都采用父AdminSite的所有默认值,而不是子实例的相关默认值。例如,我的自定义实例中设置了不同的网站标题(site_title),但是在查看任何已自动注册的模型时,仅对这些模型显示Django的默认值。文档确实说了,当使用自定义实例时,需要手动进行注册。https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.autodiscover - Aiky30
你是否尝试过 self._registry.update() 步骤,Django 在自动注册/构建其 AdminSite 后,然后你复制映射?这可能会覆盖现有的值,因此请在 __init__() 中调用该方法后设置您的 AdminSite 属性(如 site_title、header、url 等)。 - JCotton
是的,我按照您发布的所有内容都尝试过了。所以如果我理解正确,您希望我在self._registry_update之后的__init__函数中重新定义site_header等变量吗? - Aiky30
值得一试。我看了1.11的代码,和1.9是一样的。尝试在过程中使用print()或pdb断点进行检查。你可能已经全部正确(除了那个总是浪费时间的东西)。 - JCotton
1
Django 2.0中测试了这段代码。设置site_headersite_title仅适用于indexapp index页面。然而,app models仍显示为Django Administration - Da CodeKid

12

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)

如果你在多个应用中拥有模型,那么这将非常重复。它没有提供任何建议,如何使用自定义站点自动注册所有应用程序中的模型。

你可以尝试 monkey patching admin,并用你自己的内容替换 admin.site

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

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


@Alasdir 谢谢,我今天稍后会尝试这个 monkey patching,听起来应该可行。此外,手动注册肯定可以完成工作,但我需要在想要包含的每个应用程序中注册每个模型。 - gerosalesc
使用 import django.contrib.admin 对我有效 django.contrib.admin.sites.site = admin_site django.contrib.admin.site = admin_site - beruic

6

在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

1

只需在您的CustomAdminSite类中包含init方法,如下所示。

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

0

对于仍然遇到此问题的任何人:

如果您定义了自定义的AdminSite并在自定义的AdminConfig中进行配置,则不需要为自己的站点手动注册第三方模型/模型表单(请参见Django实现,了解它如何使用此功能查找适当的AdminSite

在您的示例中,现在您有了OptiAdmin,您需要定义以下内容:

# my_project.apps.py
from django.contrib.admin.apps import AdminConfig

class OptiAdminConfig(AdminConfig)
  default_site = 'my_project.admin.OptiAdmin'

然后,在您的settings.py文件中,您需要像下面这样在INSTALLED_APPS配置中设置它:
INSTALLED_APPS = [
    ...
    "my_project.apps.OptiAdminConfig",
    ...

]

现在,您应该在Django管理站点中看到由第三方应用程序注册的任何模型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接