如何向 Django 用户管理页面添加操作?

How can I add an action to the Django User admin page?

我正在使用 Django 3.0。我想在管理员中向用户更改列表添加一个操作。

admin actions 的文档表明要向管理页面添加操作,我需要将方法或对它的引用添加到 [=16= 中模型的 admin.ModelAdmin 子类]:

# admin.py
from django.contrib import admin

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'status']
    ordering = ['title']
    actions = [make_published]

# admin.py
from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    ...

    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.short_description = "Mark selected stories as published"

由于用户模型的 admin.ModelAdmin 子类在 auth 系统中而不是在我的 admin.py 中,但是,我不知道将这种情况的代码放在哪里。

我试着跟随用户 Davor Lucic 对一个更老但 similar question

的回答
from django.contrib.auth.models import User

class UserAdmin(admin.ModelAdmin):
    actions = ['activate_user','deactivate_user']

    def activate_user(self, request, queryset):
        queryset.update(is_active=True)

    def deactivate_user(self, request, queryset):
        queryset.update(is_active=False)

    activate_user.short_description = "Activate user(s)"
    deactivate_user.short_description = "Deactivate user(s)"

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

当我尝试这个时,服务器因错误而停止(响应者请求的完整堆栈跟踪):

Project/project/app/admin.py changed, reloading.
Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "Project/env/lib/python3.6/site-packages/django/utils/autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "Project/env/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 109, in inner_run
    autoreload.raise_last_exception()
  File "Project/env/lib/python3.6/site-packages/django/utils/autoreload.py", line 76, in raise_last_exception
    raise _exception[1]
  File "Project/env/lib/python3.6/site-packages/django/core/management/__init__.py", line 357, in execute
    autoreload.check_errors(django.setup)()
  File "Project/env/lib/python3.6/site-packages/django/utils/autoreload.py", line 53, in wrapper
    fn(*args, **kwargs)
  File "Project/env/lib/python3.6/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "Project/env/lib/python3.6/site-packages/django/apps/registry.py", line 122, in populate
    app_config.ready()
  File "Project/env/lib/python3.6/site-packages/django/contrib/admin/apps.py", line 24, in ready
    self.module.autodiscover()
  File "Project/env/lib/python3.6/site-packages/django/contrib/admin/__init__.py", line 26, in autodiscover
    autodiscover_modules('admin', register_to=site)
  File "Project/env/lib/python3.6/site-packages/django/utils/module_loading.py", line 47, in autodiscover_modules
    import_module('%s.%s' % (app_config.name, module_to_search))
  File "Project/env/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "Project/project/app/admin.py", line 153, in <module>
    admin.site.unregister(User)
  File "Project/env/lib/python3.6/site-packages/django/contrib/admin/sites.py", line 144, in unregister
    raise NotRegistered('The model %s is not registered' % model.__name__)
django.contrib.admin.sites.NotRegistered: The model User is not registered

我认为错误可能与 register()unregister() 函数有关,但这些函数没有文档,所以我无从知晓。

是否有一种简单有效的方法来向 auth.models.User 模型添加管理操作?

编辑: 这是最终结果,感谢 'tim-mccurrach':

from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin

class UserAdmin(AuthUserAdmin):
    actions = ['activate_user','deactivate_user']

    def activate_user(self, request, queryset):
        queryset.update(is_active=True)

    def deactivate_user(self, request, queryset):
        queryset.update(is_active=False)

    activate_user.short_description = "Activate selected users"
    deactivate_user.short_description = "Deactivate selected users"

admin.site.unregister(User)
admin.site.register(User, UserAdmin)

我检查过,使用这个方案不需要在 settings.py 中重新排序 INSTALLED_APPS(如果你的应用程序出现在 contrib.admin 和 [=26= 之前就可以了) ]).

问题是你的 INSTALLED_APPS.

的顺序

因为您的 App 应用在 contrib.auth 之前,所以 app.admin.py 文件在 conrib.auth.admin.py 文件之前导入。这意味着您正在尝试注销 User 管理员,甚至在它被注册之前。

更改 INSTALLED_APPS 顺序,将您自己的应用放在 contrib.auth 应用之后,一切正常:)

另请注意: 如果您继承自 auths UserAdmin 而不是继承自 admin.ModelAdmin,您将获得所有现有功能,例如:

from django.contrib.auth.admin import UserAdmin as OriginalUserAdmin

class UserAdmin(OriginalUserAdmin):
    actions = ['activate_user','deactivate_user']
    ... 


admin.site.unregister(User)
admin.site.register(User, UserAdmin)

碰巧,我认为在此处导入 UserAdmin 也可以解决您的问题,而无需更改 INSTALLED_APPS 顺序,因为在导入 UserAdmin 时代码将具有 运行注册旧的UserAdmin。不过,更改应用程序的顺序似乎是解决问题的更有效方法。