Django结合了DetailView和FormView [英] Django combine DetailView and FormView

查看:113
本文介绍了Django结合了DetailView和FormView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个视图,需要显示有关某个特定模型实例的信息,因此我使用了 DetailView 。我还需要使用同一视图来处理常规表单(而不是模型表单),都需要在 GET 上显示该表单,并在 POST 上对其进行验证。 code>。为此,我尝试使用 FormView ,但是两种视图分类的组合均无效:

I have a view where I need to display information about a certain model instance hence I use a DetailView. I also need that same view to handle a regular form (not a model form), both displaying the form on GET and validating it on POST. To do that, I am trying to use a FormView however the combination of both view clases does not work:

class FooView(FormView, DetailView):
    # configs here

GET 中(为简单起见,我只显示 GET 的问题,因为 POST 有一个不同的问题),它不起作用,因为表单从未添加到上下文中。原因与该类的方法解析顺序有关:

In GET (for simplicity of the question I will only show the issue with GET since POST has a different issue), it does not work because the form never gets added to the context. The reason has to do with method resolution order for that class:

>>> inspect.getmro(FooView)
(FooView,
 django.views.generic.edit.FormView,
 django.views.generic.detail.DetailView,
 django.views.generic.detail.SingleObjectTemplateResponseMixin,
 django.views.generic.base.TemplateResponseMixin,
 django.views.generic.edit.BaseFormView,
 django.views.generic.edit.FormMixin,
 django.views.generic.detail.BaseDetailView,
 django.views.generic.detail.SingleObjectMixin,
 django.views.generic.base.ContextMixin,
 django.views.generic.edit.ProcessFormView,
 django.views.generic.base.View,
 object)

在请求中,Django必须获取表单并将其添加到上下文中。发生在 ProcessFormView.get

Within the request, Django has to get the form and add it to the context. That happens in ProcessFormView.get:

def get(self, request, *args, **kwargs):
    """
    Handles GET requests and instantiates a blank version of the form.
    """
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    return self.render_to_response(self.get_context_data(form=form))

但是定义了 get 的具有MRO的第一类是 BaseDetailView

However the first class with the MRO which has get defined is BaseDetailView:

def get(self, request, *args, **kwargs):
    self.object = self.get_object()
    context = self.get_context_data(object=self.object)
    return self.render_to_response(context)

您可以看到 BaseDetailView.get 从不调用 super ,因此 ProcessFormView.get 永远不会被调用,因此表单不会添加到上下文中。可以通过创建一个混合视图来解决此问题,在该视图中,可以照顾到所有用于 GET POST 的细微差别。

As you can see the BaseDetailView.get never calls super hence the ProcessFormView.get will never be called hence the the form will not be added to the context. This can be fixed by creating a mixin view where all these nuances for GET and POST can be taken care of however I do not feel it is a clean solution.

我的问题:是否可以通过Django的默认CBV实现来实现我想要的功能而无需创建任何混合包?

My question: is there any way of accomplishing what I want with Django's default CBV implementation without creating any mixins?

推荐答案

一种解决方案是按照上面的lilightlights的评论使用mixins。

One solution would be to use mixins, as per limelights' comment above.

另一种方法是拥有两个单独的视图,一个为 DetailView ,另一个为 FormView 。然后,在前者的模板中,显示您在后者中使用的相同表单,除了您不会将 action 属性留空-而是设置将其添加到 FormView 的网址中。与此类似的事情(请注意当我在编写本文时没有进行任何测试的任何错误):

Another approach is to have two separate views, one a DetailView and the other a FormView. Then, in the template for the former, display the same form you're using in the latter, except that you won't leave the action attribute empty -- instead, set it to the url for the FormView. Something along the lines of this (please beware of any errors as I'm writing this without any testing):

views.py

class MyDetailView(DetailView):
    model = MyModel
    template_name = 'my_detail_view.html'

    def get_context_data(self, **kwargs):
        context = super(MyDetailView, self).get_context_data(**kwargs)
        context['form'] = MyFormClass
        return context

class MyFormView(FormView):
    form_class = MyFormClass
    success_url = 'go/here/if/all/works'

my_detail_view.html

<!-- some representation of the MyModel object -->

<form method="post" action="{% url "my_form_view_url" %}">

{{ form }}

</form>

urls.py 中:

# ...
url('^my_model/(?P<pk>\d+)/$', MyDetailView.as_view(), name='my_detail_view_url'),
url('^my_form/$', require_POST(MyFormView.as_view()), name='my_form_view_url'),
# ...

请注意, require_POST 装饰器是可选的,在如果您不希望 GET 访问 MyFormView ,并且只希望在表单已提交。

Note that the require_POST decorator is optional, in the case that you don't want the MyFormView to be accessible by GET and want it only to be processed when the form is submitted.

这篇关于Django结合了DetailView和FormView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆