Python使用模型继承重用视图和表单

时间:2016-01-22 19:52:44

标签: python django

首先,我对Python& Django,所以这可能是一个简单的问题。现在,我有一个这样的模型:

models.py

class Base(models.Model):
    class Meta:
        abstract = True
    # base properties

class X(Base):
    # extra props

class Y(Base):
    # extra props

然后我想要一个X的视图和一个Y的视图,它基本上会做同样的事情,例如:

views.py

class BaseView(object):
    template_name = "app/view.html"

    Type = None

    def __init__(self, type):
        self.Type = type

    def get_context_data(self, **kwargs):
        context = super(BaseView, self).get_context_data(**kwargs)
        context['data'] = get_object_or_404(self.Type, pk=kwargs["id"])
        return context


class XView(BaseView, generic.TemplateView):
    def __init__(self):
        BaseView.__init__(self, X)

class YView(BaseView, generic.TemplateView):
    def __init__(self):
        BaseView.__init__(self, Y)

urls.py

urlpatterns = [
    url(r'^xxxx/(?P<id>[0-9]+)$', views.XView.as_view(), name="view_x"),
    url(r'^yyyy/(?P<id>[0-9]+)$', views.YView.as_view(), name="view_y"),
]

像这样,我将不得不重复所有(或大部分)表格,观点等。反正有没有避免这种重复? X和Y之间的差异只是表格中由django完美生成的几个字段。

我需要根据URL区分模型,例如:/ x /或example.com/Y/,其他所有内容都差不多。

仅供参考,使用Python 3,Django 1.9。

2 个答案:

答案 0 :(得分:2)

您应该按照它们应该使用的方式使用Django通用视图类。如果您的所有类都在根据URL中的ID将对象传递给模板,则应使用内置的DetailView类;然后,您可以直接在URLconf中将模型和模板名称作为参数传递,而无需根据需要定义子类。

from django.views.generic import DetailView
urlpatterns = [
    url(r'^xxxx/(?P<pk>[0-9]+)$', DetailView.as_view(model=X, template_name = "app/view.html"), name="view_x"),
    url(r'^yyyy/(?P<pk>[0-9]+)$', DetailView.as_view(model=X, template_name = "app/view.html"), name="view_y"),
]

(注意DetailView期望URL参数被称为pk而不是id。)

如果您确实想为视图添加更多自定义行为,则可以继承DetailView;在多种URL模式中使用相同的视图类仍然是完全可能的。

答案 1 :(得分:1)

您可以通过几种方式删除重复项。在您的urls.py中,您可以将参数直接传递给您的视图:

# urls.py
urlpatterns = [
    url(r'^xxxx/(?P<id>[0-9]+)$', views.BaseView.as_view(Type=X), name="view_x"),
    url(r'^yyyy/(?P<id>[0-9]+)$', views.BaseView.as_view(Type=Y), name="view_x"),
]

这样,您就不需要定义XViewYView。您可以更进一步,并使用您的URL参数进行模型。

# urls.py
urlpatterns = [
    url(r'^(?P<model>\w+)/(?P<id>[0-9]+)$', views.BaseView.as_view(), name='view_base'),
]

# views.py
class BaseView(View):

    type_map = {
        'xxxx': X,
        'yyyy': Y,
    }

    def dispatch(self, request, *args, **kwargs):
        model = kwargs.get('model')
        self.type = self.type_map.get(model)
        if self.type is None:
            raise Http404
        return super(BaseView, self).dispatch(request, *args, **kwargs)