长话短说
在使用 ModelAdmin.get_urls
和 ModelAdmins
通过继承扩展时,是否有一种方法可以定义(命名空间)命名良好的 View ?
最好不要求助于 ModelAdmin.model._meta
或其他一些稍微有问题的解决方案。
借口
在使用和继承自定义 ModelAdmins
时,通过 get_urls
添加的 View 名称会被覆盖。
也就是说, View 名称 admin:tighten
在以下示例中被覆盖:
class Screw(models.Model):
"A screw"
class HexCapScrew(Screw):
"A hex cap screw"
class ScrewAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(ScrewAdmin, self).get_urls()
extra_urls = patterns('',
url(r'^tighten/$', self.tighten, name='tighten'),
)
return extra_urls + urls
def tighten(self, request):
pass
class HexCapScrewAdmin(ScrewAdmin):
pass
admin.site.register(Screw, ScrewAdmin)
admin.site.register(HexCapScrew, HexCapScrewAdmin)
在 shell 上会发生以下情况:
In [1]: reverse('admin:tighten')
Out[1]: u'/admin/parts/hexscrew/tighten/'
这当然是可以理解的,因为 HexCapScrewAdmin
的注册覆盖了 ScrewAdmin
中的tighten
,但是现在不可能逆转 ScrewAdmin。收紧
。
首选解决方案
但是我希望能够
- 分别引用两个 View 和
- 最好在自己的实例命名空间中拥有 View 。
到目前为止的进展
我想到的最好的设置是以下设置(可以直接复制粘贴到某些应用程序进行测试):
from django.contrib import admin
from django.db import models
class Screw(models.Model):
"A screw"
class Meta:
app_label = 'parts'
class HexCapScrew(Screw):
"A hex cap screw"
class Meta:
app_label = 'parts'
proxy = True
class ScrewAdmin(admin.ModelAdmin):
def tighten(self, request):
pass
def get_urls(self):
urls = super(ScrewAdmin, self).get_urls()
extra_urls = patterns('',
url(r'^tighten/$', self.tighten, name='tighten'),
)
# Find out the slugified name of the model this admin is bound to
# TODO: Feels dirty
model_name = self.model._meta.model_name
# Add the to `extra_urls` to their own namespace
namespaced_extra_urls = patterns('',
url(r'^', include(extra_urls, namespace=model_name, app_name='screw')),
)
return namespaced_extra_urls + urls
class HexCapScrewAdmin(ScrewAdmin):
pass
admin.site.register(Screw, ScrewAdmin)
admin.site.register(HexCapScrew, HexCapScrewAdmin)
现在我有以下内容:
In [1]: reverse('admin:screw:tighten')
Out[1]: u'/admin/parts/screw/tighten/'
In [2]: reverse('admin:hexscrew:tighten')
Out[2]: u'/admin/parts/hexscrew/tighten/'
In [3]: reverse('admin:screw:tighten', current_app='hexscrew')
Out[3]: u'/admin/parts/hexscrew/tighten/'
这很好用,但包含一些 hackery。
这是可用的最好的还是我只是遗漏了什么?有什么建议吗?
(至少还有一种方法是像 Django 的 ModelAdmin.get_urls
使用 ModelAdmin.model._meta
到 parametrize the view names 那样,但我会使用命名空间。 )
最佳答案
如果你看看管理员做这件事的方式here ,您会看到除了定义 url 之外,模型管理员还将 app_label 和 model_name 作为 url 名称的前缀,从而避免了子类化问题。它还具有防止未授权用户访问 View 的优势(使用 self.admin_site.admin_view
装饰器)。您的 get_urls()
方法将变为:
def get_urls(self):
from django.conf.urls import url
def wrap(view):
def wrapper(*args, **kwargs):
return self.admin_site.admin_view(view)(*args, **kwargs)
return update_wrapper(wrapper, view)
info = self.model._meta.app_label, self.model._meta.model_name
urlpatterns = super(ScrewAdmin, self).get_urls()
urlpatterns.append(
url(r'^tighten/$', wrap(self.tighten), name='%s_%s_tighten' % info))
return urlpatterns
然后,您可以像这样查找您的网址:reverse('admin:app_screw_tighten')
或 reverse('admin:app_hex_screw_tighten')
。
关于python - 使用模型(管理)继承时命名空间 ModelAdmin.get_urls 的 Django 方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21125734/