【问题标题】:Override Django Admin URLs for Specific Model?覆盖特定模型的 Django 管理 URL?
【发布时间】:2011-08-06 12:41:13
【问题描述】:

先介绍一点背景:

我有一个Event 模型,它有各种event_types。我想将其中一种事件类型“电影”分解为它自己的管理员。我有一个基本功能:继承自 Event 的代理模型,命名为 Film,该代理模型的自定义管理器将其过滤为仅“电影”事件类型,它是自己的 ModelAdmin。

问题是反过来的。我现在需要从主 Event 管理员中过滤掉电影。我不想更改Event 模型或其默认管理器,因为影响太广泛了。因此,我尝试创建另一个代理模型EventAdminProxy,其唯一目的是在管理员中提供过滤的事件列表。然后我用现有的 ModelAdmin 注册这个模型,而不是 Event

这显然有效,但它有一个不幸的副作用,即在管理员中更改 URL。变更列表不再位于“/admin/event/event/”,而是位于“/admin/event/eventadminproxy/”。

我要做的是保留此设置,但也要保留旧 URL。我尝试重载 ModelAdmin 的 get_urls 方法,但据我所知,您无法控制那里的完整 URL,只能控制“/app_label/model_class/”部分之后的内容。

我曾考虑在主 urls.py 中覆盖它,但无法找到一个可接受的视图来绑定。实际视图仅在实例化的 ModelAdmin 对象上可用,而不是类本身。

关于如何覆盖管理员中使用的 URL 的任何想法?

【问题讨论】:

    标签: django url django-admin django-urls


    【解决方案1】:

    您可以覆盖 EventModelAdminqueryset-method 并过滤查询集,以便排除电影事件。

    类似的东西:

    class EventAdmin(admin.ModelAdmin):
    
        def queryset(self, request):
            qs = super(EventAdmin, self).queryset(request)
            return qs.exclude(event_type='film')
    

    【讨论】:

    • 好的。将那个添加到“我是个白痴”类别中。不敢相信我没有想到这一点。谢谢!
    【解决方案2】:

    查看 Django 源代码,管理 URL 构建在两个地方,在 ModelAdmin 实例和 AdminSite 实例中。

    您要更改的部分内置在 AdminSite 实例 (django.contrib.admin.sites.AdminSite) 中,您可以对其进行子类化并覆盖 get_urls 方法。如果您查看该方法的后半部分,您会看到:

        # Add in each model's views.
        for model, model_admin in self._registry.iteritems():
            urlpatterns += patterns('',
                url(r'^%s/%s/' % (model._meta.app_label, model._meta.module_name),
                    include(model_admin.urls))
            )
    

    它添加了模型的 ._meta.module_name ,它只是模型名称的小写 (django.db.models.options.Options.contribute_to_class)。

    一个简单的方法是覆盖站点的 get_urls 方法并为代理模型添加一个字典或特殊情况,以便它使用不同的 url 而不是 model._meta.module_name,类似的东西:

    类 MyAdminSite(AdminSite):

    module_name_dict = {
        EventAdminProxy: 'myfunkymodulename'
    }
    
    def get_urls(self):
        base_patterns = super(MyAdminSite, self).get_urls()
        my_patterns = patterns('',)
    
        for model, model_admin in self._registry.iteritems():
            if model in self.module_name_dict:
                module_name = self.module_name_dict[model]
                my_patterns += patterns('',
                    url(r'^%s/%s/' % (model._meta.app_label, module_name),
                        include(model_admin.urls))
                )
    
        return my_patterns + base_patterns
    

    【讨论】:

      【解决方案3】:

      您还可以继承 ChangeList 并覆盖 url_for_result() 方法来自定义更改 url,(从 another answer 学习),例如:

      from django.contrib.admin.views.main import ChangeList
      
      class FooChangeList(ChangeList):
          def url_for_result(self, obj):
              return '/foos/foo/{obj.pk}/'
      
      class FooAdmin(admin.ModelAdmin):
          def get_changelist(self, request, **kwargs):
              return FooChangeList
      

      问题的改编示例:

      from django.contrib.admin.views.main import ChangeList
      from django.urls import reverse
      
      class FilmAdmin(admin.ModelAdmin):
          def get_changelist(self, request, **kwargs):
              class FilmChangeList(ChangeList):
                  def url_for_result(self, obj):
                      return reverse('admin:events_event_change', args=(obj.pk, ))
              return FilmChangeList
      

      【讨论】:

        猜你喜欢
        • 2010-11-19
        • 2013-01-23
        • 2011-12-10
        • 1970-01-01
        • 2016-04-28
        • 1970-01-01
        • 2011-07-26
        • 2020-02-14
        • 2018-10-22
        相关资源
        最近更新 更多