【问题标题】:Django - Extending another apps ModelAdmin?Django - 扩展另一个应用程序 ModelAdmin?
【发布时间】:2010-01-31 04:05:10
【问题描述】:

有没有办法扩展其他应用的 ModelAdmin?

我有一个项目使用 django.contrib.cmets 提供的功能。

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.cmets 代码的情况下做到这一点?

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    这是我在一个用户模型项目中的做法。在我的应用的 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)
    

    【讨论】:

      【解决方案2】:

      UnregisterComment 模型优先。

      【讨论】:

        【解决方案3】:

        我猜你的文件顶部有这样的内容:

        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 中的 cmets 应用程序之后。

        现在上课。我认为如果您写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:你确定吗?我试图让 Geodjango 的地图小部件在前端工作。为此,我需要导入在我的 admin.py 文件中定义的自定义 AdminModel。当我导入这个类时,admin.site.register 函数又被执行了。这就是我的观点。当您尝试导入该类时,它会尝试再次注册该模型。你成功了吗?如果有其他解决方案,我会非常高兴。
        • 如果模块通过两个不同的路径导入,模块级代码只会执行两次。一般来说,这不应该发生。我不知道 GeoDjango 是否做了一些时髦的事情,从未使用过它。请参阅我在生产中使用的简单版本的答案。
        • @Carl Meyer:检查我是否理解正确:假设管理员的auto_detect() 函数通过from project.app import admin 导入我的admin.py,我通过from app.admin import ModelAdmin 将它导入到同一个应用程序中,然后代码被执行两次?如果是这样,那么我描述的问题只有在你想覆盖自定义 ModelAdmins 以导入 django contrib 东西时才会出现,你总是使用相同的路径。
        • 我没有看细节。我假设您可以通过简单的方式覆盖任何 ModelAdmin,可能只需要调整您使用的导入样式。
        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2016-04-01
          • 1970-01-01
          • 2021-06-29
          • 1970-01-01
          • 1970-01-01
          • 2012-01-15
          • 1970-01-01
          • 2018-03-24
          • 1970-01-01
          相关资源
          最近更新 更多