为项目而非应用的admin.py
我该如何指定一个项目级别的 admin.py 文件呢?
我之前问过这个问题,结果因为没有人回复,我还得了个“干枯草”的奖!>_<
项目结构:
- settings.py
- admin.py(这是我想让它工作的文件)
- ...
- 应用
- admin.py(这个我知道怎么做)
比如,admin.autodiscover()
通常放在项目级别的 urls.py
文件里(是的,从 1.7 版本开始,它会自动包含)。
我想把这个和下面的内容放到自己的 admin.py
文件里:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
UserAdmin.list_display = ('email', 'first_name', 'last_name', 'is_active')
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.autodiscover()
我试着这么做,创建了一个 admin.py
文件并把代码放进去,但没成功。
我还试着创建一个名为 admin
的项目级文件夹,添加了一个 __init__.py
文件,然后把 admin.py
放进这个文件夹里,但还是不行。
然后我又尝试把这个 admin
文件夹添加到 settings.py
的 INSTALLED_APPS
里,但也没成功。
4 个回答
我很好奇这个会不会被投反对票。看起来是有效的,但感觉有点不对劲。;-)
问题是如何覆盖 UserAdmin 的设置。
- 在你的项目文件夹里放一个 admin.py 文件(和 settings.py 在同一个地方)
from django.contrib.auth import admin
from django.contrib.auth.admin import UserAdmin
UserAdmin.list_display = ('email', 'first_name', 'last_name',
'is_active', 'date_joined', 'last_login',
'is_staff')
UserAdmin.ordering = ['-date_joined']
- 把你的项目添加到 installed_apps 里(这看起来不太对,但我不知道为什么)
现在你应该能在 /admin/auth/user/ 上看到新的列和排序方式。
我在使用 Django 1.11 时这样做是有效的。到目前为止,我没有发现什么问题。你们怎么看,StackOverflow?
迟早,一个高度自定义的 admin
类可能需要一个全项目通用的 admin.py
文件,因为这个文件是用来注册所有不再自动发现的每个应用的管理后台的地方。文档中提到了这一点,但没有详细的例子来说明:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#customizing-the-adminsite-class
请注意,当你使用自己的
AdminSite
实例时,可能不希望自动发现admin
模块,因为你很可能会在你的myproject.admin
模块中导入所有每个应用的admin
模块。这意味着你需要在INSTALLED_APPS
设置中放入'django.contrib.admin.apps.SimpleAdminConfig'
,而不是'django.contrib.admin'
。
在维基上还有一个稍微过时但大致有效的例子,适用于多个 admin
网站:
https://code.djangoproject.com/wiki/NewformsAdminBranch
# project-level admin.py
from django.contrib import admin
from myproject.myapp.models import Book, Author
from myproject.anotherapp.models import Musician, Instrument
site1 = admin.AdminSite()
site1.register(Book)
site1.register(Author)
site2 = admin.AdminSite()
site2.register(Musician)
site2.register(Instrument)
来自 admin.autodiscover
的文档说明:
自动发现已安装应用的 admin.py 模块,如果没有找到则不会报错。这会强制导入这些模块,以注册它们可能需要的任何管理功能。
下面是这个功能的完整代码,并且有很好的注释:
def autodiscover():
"""
Auto-discover INSTALLED_APPS admin.py modules and fail silently when
not present. This forces an import on them to register any admin bits they
may want.
"""
import copy
from django.conf import settings
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule
for app in settings.INSTALLED_APPS:
mod = import_module(app)
# Attempt to import the app's admin module.
try:
before_import_registry = copy.copy(site._registry)
import_module('%s.admin' % app)
except:
# Reset the model registry to the state before the last import as
# this import will have to reoccur on the next request and this
# could raise NotRegistered and AlreadyRegistered exceptions
# (see #8245).
site._registry = before_import_registry
# Decide whether to bubble up this error. If the app just
# doesn't have an admin module, we can ignore the error
# attempting to import it, otherwise we want it to bubble up.
if module_has_submodule(mod, 'admin'):
raise
所以,autodiscover 主要的作用就是在已安装的应用目录中寻找名为 admin.py
的模块。因此,你可以把你的 admin.py 放在任何地方,只要确保你导入了它,这样里面的代码(比如模型注册等)就会被执行。
重要提示:我不太确定导入你自定义路径的 admin.py
的正确时机。但可以肯定的是,你必须在加载所有相关应用之后再导入它。
所有的 admin.autodiscover()
其实就是把它找到的所有管理文件都导入进来。把这行代码放在管理文件里是没有意义的。
要理解为什么它不工作,你需要知道它是怎么运作的。它的作用是导入那些在已注册应用里的 admin.py 文件。已注册的应用是指在 INSTALLED_APPS 中包含的包,并且这个包里必须有一个 models.py 文件。值得强调的是:如果没有 models.py,那个包就不算是一个应用——即使是空的 models.py 也可以,但没有它,这个包就不算应用。
所以,如果你在你的目录里创建一个空的 models.py,确保这个目录在 INSTALLED_APPS 中,并把 admin.autodiscover 移回 urls.py,所有东西就会正常工作了。
补充说明
我不太确定你想要什么,以及为什么想要这样。正如我提到的,autodiscover 是依赖于应用的;但我也提到过,autodiscover 只是导入所有的管理文件。如果你真的不想遵循最佳实践,你只需要手动导入你的管理文件:你可以在通常调用 autodiscover 的地方,也就是在主 urls.py 里进行导入。