Django结合了DetailView和FormView [英] Django combine DetailView and 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屋!