覆盖特定模型的Django管理员URL?

时间:2011-04-15 17:40:23

标签: django url django-admin django-urls

首先是一点背景:

我的Event模型有各种event_type个。我想打破其中一个事件类型,'电影',进入它自己的管理员。我有基本的功能:继承自Event的代理模型,名为Film,该代理模型的自定义管理器将其过滤为“电影”事件类型,并且它是自己的ModelAdmin。 / p>

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

这显然有效,但它在更改管理员中的URL时会产生令人遗憾的副作用。而不是更改列表位于“/ admin / event / event /”,它现在位于“/ admin / event / eventadminproxy /".

我要做的是保留此设置,但也保留旧网址。我已经尝试重载ModelAdmin的get_urls方法,但从我所知道的,你无法控制那里的完整URL,只能在“/ app_label / model_class /”部分之后控制。

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

有关如何覆盖管理员中使用的网址的任何想法?

3 个答案:

答案 0 :(得分:8)

查看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方法,并为代理模型添加一个字典或特殊情况,以便它使用不同的网址而不是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

答案 1 :(得分:6)

您可以覆盖EventModelAdmin的{​​{3}}并过滤查询集,以便排除电影事件。

类似的东西:

class EventAdmin(admin.ModelAdmin):

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

答案 2 :(得分:0)

您还可以继承ChangeList的子类,并覆盖url_for_result()方法以自定义更改网址(从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