python - 使用模型(管理)继承时命名空间 ModelAdmin.get_urls 的 Django 方式是什么?

标签 python django inheritance namespaces django-admin

长话短说

在使用 ModelAdmin.get_urlsModelAdmins 通过继承扩展时,是否有一种方法可以定义(命名空间)命名良好的 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。收紧

首选解决方案

但是我希望能够

  1. 分别引用两个 View 和
  2. 最好在自己的实例命名空间中拥有 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._metaparametrize 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/

相关文章:

jquery - AJAX 请求时 Django 表单无效(form.is_valide() 返回 False)

c++ - 从我正在扩展的嵌套类中覆盖方法

python - 找到每个数字恰好只有一次并且能被 11 整除的最大数(在一个范围内)

django - 图表未在 django-nvd3 中呈现

python - wxpython 将多个 wx.NumCtrl 放入数据结构中以便在 matplotlib 中绘图

python - 向 django 添加新应用

java - 如何从父类继承变量?

java - 为什么没有找到方法?

python - Django 的数据库表名

python - 如何在 64 位 Windows 7 机器上安装 pycrypto?