【问题标题】:Multiple ModelAdmins/views for same model in Django adminDjango admin 中同一模型的多个 ModelAdmins/视图
【发布时间】:2011-01-14 11:13:40
【问题描述】:

如何为同一个模型创建多个 ModelAdmin,每个模型都以不同方式定制并链接到不同的 URL?

假设我有一个名为 Posts 的 Django 模型。默认情况下,此模型的管理视图将列出所有 Post 对象。

我知道我可以通过设置 list_display 之类的变量或覆盖我的 ModelAdmin 中的 queryset 方法,以各种方式自定义页面上显示的对象列表,如下所示:

class MyPostAdmin(admin.ModelAdmin):
    list_display = ('title', 'pub_date')

    def queryset(self, request):
        request_user = request.user
        return Post.objects.filter(author=request_user)

admin.site.register(MyPostAdmin, Post)

默认情况下,可以通过 URL /admin/myapp/post 访问。但是我想拥有同一个模型的多个视图/模型管理员。例如,/admin/myapp/post 会列出所有帖子对象,/admin/myapp/myposts 会列出属于用户的所有帖子,/admin/myapp/draftpost 可能会列出所有尚未发布的帖子。 (这些只是示例,我的实际用例更复杂)

您不能为同一模型注册多个 ModelAdmin(这会导致AlreadyRegistered 异常)。理想情况下,我希望将所有内容放入单个 ModelAdmin 类并编写我自己的“urls”函数以根据 URL 返回不同的查询集。

我查看了 Django 源代码,发现像 ModelAdmin.changelist_view 这样的函数可能会以某种方式包含在我的 urls.py 中,但我不确定它究竟是如何工作的。

更新:我找到了一种做我想做的事的方法(见下文),但我仍然想听听其他方法。

【问题讨论】:

    标签: python django django-admin


    【解决方案1】:

    我找到了一种方法来实现我想要的,通过使用代理模型来解决每个模型只能注册一次的事实。

    class PostAdmin(admin.ModelAdmin):
        list_display = ('title', 'pubdate','user')
    
    class MyPost(Post):
        class Meta:
            proxy = True
    
    class MyPostAdmin(PostAdmin):
        def get_queryset(self, request):
            return self.model.objects.filter(user = request.user)
    
    
    admin.site.register(Post, PostAdmin)
    admin.site.register(MyPost, MyPostAdmin)
    

    那么默认的PostAdmin 可以通过/admin/myapp/post 访问,用户拥有的帖子列表将在/admin/myapp/myposts

    看了http://code.djangoproject.com/wiki/DynamicModels之后,我想出了以下函数实用函数来做同样的事情:

    def create_modeladmin(modeladmin, model, name = None):
        class  Meta:
            proxy = True
            app_label = model._meta.app_label
    
        attrs = {'__module__': '', 'Meta': Meta}
    
        newmodel = type(name, (model,), attrs)
    
        admin.site.register(newmodel, modeladmin)
        return modeladmin
    

    可以这样使用:

    class MyPostAdmin(PostAdmin):
        def get_queryset(self, request):
            return self.model.objects.filter(user = request.user)
    
    create_modeladmin(MyPostAdmin, name='my-posts', model=Post)
    

    【讨论】:

    • 这太棒了。我不知道可以在管理站点中注册代理模型。这实际上对我有很大帮助。
    • 我还需要在 django admin 中注册两次相同的模型,并且代理模型似乎可以工作。但是我发现权限系统有一个问题。见这里:code.djangoproject.com/ticket/11154
    • 更改默认管理器而不是 ModelAdmin 查询集也是一个好主意。因此,即使在管理员之外,代理模型的行为也是一致的。
    • 现在真正的答案是,为什么 django 不允许您为同一模型设置两个管理员?我们不应该只用两行来检查并抛出错误:s。答案仍然很好!
    • @zzart:有一个待处理的拉取请求,似乎只是缺少文档:github.com/django/django/pull/146/files
    【解决方案2】:

    Paul Stone 的回答绝对棒极了!补充一点,对于 Django 1.4.5,我需要从 admin.ModelAdmin 继承我的自定义类

    class MyPostAdmin(admin.ModelAdmin):
        def queryset(self, request):
            return self.model.objects.filter(id=1)
    

    【讨论】:

      【解决方案3】:

      根据正确答案,我猴子补丁AdminSite 类并添加方法register_via_proxy 以使任务更容易。

      import re
      from django.contrib import admin
      
      def _register_proxy(self, model, admin_class):
          proxy_model = type(
              admin_class.__name__, (model,), {
                  "__module__": re.sub(
                      r'(^.*?)(\.[^\.]+)$', r'\1.proxy', model.__module__
                  ),
                  "Meta": type("Meta", tuple(), {
                      "proxy": True,
                       "app_label": model._meta.app_label
                  })
              }
          )
      
          return self.register(proxy_model, admin_class)
      
      
      admin.sites.AdminSite.register_via_proxy = _register_proxy
      

      使用方法如下:

      site = admin.sites.AdminSite()
      site.register_via_proxy(models.ModelType, AdminClass)
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-09
        • 1970-01-01
        • 2012-01-25
        • 2011-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多