Django - 扩展另一个应用程序的ModelAdmin?

16
有没有一种方法可以扩展另一个应用程序的ModelAdmin?
我有一个使用django.contrib.comments提供的功能的项目。 CommentsAdmin ModelAdmin类有: “actions = [“ flag_comments”,“ approve_comments”,“ remove_comments”]” 我想在我的项目中扩展CommentsAdmin ModelAdmin,以包括一个操作“ ban_user”。
我尝试在我的admin.py文件中创建自己的NewCommentsAdmin(CommentsAdmin)对象并注册它,但是我收到一个通知:“AlreadyRegistered at /admin/ 'The model Comment is already registered'”。
class NewCommentAdmin(CommentAdmin):
    actions = ['ban_user']

    def ban_user(self, request, queryset):
        pass

admin.site.register(Comment, NewCommentAdmin)

有没有一种方法可以在不修改原始的django.contrib.comments代码的情况下实现这一点?

4个回答

12

以下是我在一个项目中为用户模型(User model)执行的操作。在我的应用程序(admin.py)中:

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

class MyUserAdmin(UserAdmin):
    # ...

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

5

4
我猜你在文件顶部有类似这样的代码:
```html

我猜你在文件顶部有类似这样的代码:

```
from django.contrib.comments.admin import CommentAdmin

这个导入执行了模型的注册(在此管理文件的底部),再次进行注册。

一个不太好看的想法(我实际上还没有尝试过)可能是:

from django.contrib.comments.models import Comment
from django.contrib import admin
from django.contrib.admin.sites import NotRegistered

# Try to unregister the Comment model 
# that was registered via the auto_discover method
try:
    admin.site.unregister(Comment)
except NotRegistered:
    pass

# Now we can load the CommentAdmin (which reregisters the admin model)
from django.contrib.comments.admin import CommentAdmin

# We have to unregister again:
try:
    admin.site.unregister(Comment)
except NotRegistered:
    pass

# Now your stuff...

我觉得这个方法可以更好地实现,但它应该能够工作。为了使这种方法有效,包含此文件的应用程序必须在INSTALLED_APPS中在评论应用程序之后。

现在看你的类。我认为如果你写actions = ['ban_user'],你实际上覆盖了父类中的所有操作。我认为最简单的方法是重写get_actions方法:

class NewCommentAdmin(CommentAdmin):

    def get_actions(self, request):
        actions = super(NewCommentAdmin, self).get_actions(request)

        # Do some logic here based on request.user if you want 
        # to restrict the new action to certain users
        actions.append('ban_user')

        return actions

    def ban_user(self, request, queryset):
        pass

admin.site.register(Comment, NewCommentAdmin)

希望这可以有所帮助(或者至少给您提供了一个思路):)

这比必要的要复杂得多。只需导入CommentAdmin,对其进行子类化,注销一次,然后注册您的版本即可。 - Carl Meyer
@Carl Meyer:你确定吗?我试图让Geodjango的地图小部件在前端工作。为此,我需要导入在我的admin.py文件中定义的自定义AdminModel。当我导入这个类时,admin.site.register函数再次被执行。这就是我的观点。当您尝试导入该类时,它会尝试重新注册该模型。你成功地让它工作了吗?如果有其他解决方案,我很乐意听取。 - Felix Kling
如果模块通过两个不同的路径导入,则模块级别的代码只会执行两次。通常情况下,这种情况不应该发生。我不知道GeoDjango是否会做一些奇怪的事情,因为我从未使用过它。请参见我的答案,其中包含我在生产中运行的简单版本。 - Carl Meyer
@Carl Meyer:确认一下我的理解是否正确:假设管理员的auto_detect()函数通过from project.app import admin导入了我的admin.py,而我在同一个应用程序中通过from app.admin import ModelAdmin导入它,那么这段代码会被执行两次?如果是这样的话,那么我描述的问题只会在你想要覆盖自定义ModelAdmin时出现,因为对于导入django contrib stuff,你总是使用相同的路径。 - Felix Kling
我还没有仔细研究过。我认为你可以通过简单的方式覆盖任何ModelAdmin来使其工作,可能只需要调整你使用的导入样式。 - Carl Meyer
太棒了,Felix。我进行了一些微调以使其运行:class NewCommentAdmin(CommentAdmin): def get_actions(self, request): self.actions.append('ban_user') return super(NewCommentAdmin, self).get_actions(request)def ban_user(self, request, queryset): for u in queryset: passadmin.site.unregister(Comment) admin.site.register(Comment, NewCommentAdmin) - Aaron C. de Bruyn

0

看一下https://github.com/kux/django-admin-extend

它提供了一些易于使用的函数和装饰器,以非常灵活的方式实现您所请求的功能。文档在解释为什么使用这种方法比直接继承更好方面做得相当不错。

它还支持注入双向多对多字段。


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