覆盖特定模型的 Django 管理 URL?
Posted
技术标签:
【中文标题】覆盖特定模型的 Django 管理 URL?【英文标题】:Override Django Admin URLs for Specific Model? 【发布时间】:2011-08-06 12:41:13 【问题描述】:先介绍一点背景:
我有一个Event
模型,它有各种event_type
s。我想将其中一种事件类型“电影”分解为它自己的管理员。我有一个基本功能:继承自 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 的任何想法?
【问题讨论】:
【参考方案1】:您可以覆盖 EventModelAdmin
的 queryset-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
【讨论】:
以上是关于覆盖特定模型的 Django 管理 URL?的主要内容,如果未能解决你的问题,请参考以下文章
为我的应用程序之外的单个模型覆盖 django 管理员更改表单?
如何在 django 管理面板中完全自定义 sidebar_menu?