Python 在Django中一页处理多个表单的正确方法
我有一个模板页需要两个表单。如果我只使用一种形式,情况就很好,如以下典型示例所示:Python 在Django中一页处理多个表单的正确方法,python,django,forms,Python,Django,Forms,我有一个模板页需要两个表单。如果我只使用一种形式,情况就很好,如以下典型示例所示: if request.method == 'POST': form = AuthorForm(request.POST,) if form.is_valid(): form.save() # do something. else: form = AuthorForm() 但是,如果我想处理多个表单,如何让视图知道我只提交了其中一个表单,而没有提交另一个表单
if request.method == 'POST':
form = AuthorForm(request.POST,)
if form.is_valid():
form.save()
# do something.
else:
form = AuthorForm()
但是,如果我想处理多个表单,如何让视图知道我只提交了其中一个表单,而没有提交另一个表单(即,它仍然是request.POST,但我只想处理提交的表单)
这是基于答案的解决方案,其中expectedphrase和BanndPhrase是不同表单的提交按钮名称,expectedphraseform和BanndPhraseForm是表单名称
if request.method == 'POST':
if 'bannedphrase' in request.POST:
bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
if bannedphraseform.is_valid():
bannedphraseform.save()
expectedphraseform = ExpectedPhraseForm(prefix='expected')
elif 'expectedphrase' in request.POST:
expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
if expectedphraseform.is_valid():
expectedphraseform.save()
bannedphraseform = BannedPhraseForm(prefix='banned')
else:
bannedphraseform = BannedPhraseForm(prefix='banned')
expectedphraseform = ExpectedPhraseForm(prefix='expected')
您有几个选择:
未来参考的方法是这样的。bannedphraseform是第一种形式,expectedphraseform是第二种形式。如果命中第一个,则跳过第二个(在这种情况下这是一个合理的假设):
Django基于类的视图提供了一个通用的FormView,但出于所有目的,它被设计为只处理一个表单 使用Django的通用视图处理具有相同目标操作url的多个表单的一种方法是扩展“TemplateView”,如下所示;我经常使用这种方法,已经将其制作成一个EclipseIDE模板
class NegotiationGroupMultifacetedView(TemplateView):
### TemplateResponseMixin
template_name = 'offers/offer_detail.html'
### ContextMixin
def get_context_data(self, **kwargs):
""" Adds extra content to our template """
context = super(NegotiationGroupDetailView, self).get_context_data(**kwargs)
...
context['negotiation_bid_form'] = NegotiationBidForm(
prefix='NegotiationBidForm',
...
# Multiple 'submit' button paths should be handled in form's .save()/clean()
data = self.request.POST if bool(set(['NegotiationBidForm-submit-counter-bid',
'NegotiationBidForm-submit-approve-bid',
'NegotiationBidForm-submit-decline-further-bids']).intersection(
self.request.POST)) else None,
)
context['offer_attachment_form'] = NegotiationAttachmentForm(
prefix='NegotiationAttachment',
...
data = self.request.POST if 'NegotiationAttachment-submit' in self.request.POST else None,
files = self.request.FILES if 'NegotiationAttachment-submit' in self.request.POST else None
)
context['offer_contact_form'] = NegotiationContactForm()
return context
### NegotiationGroupDetailView
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if context['negotiation_bid_form'].is_valid():
instance = context['negotiation_bid_form'].save()
messages.success(request, 'Your offer bid #{0} has been submitted.'.format(instance.pk))
elif context['offer_attachment_form'].is_valid():
instance = context['offer_attachment_form'].save()
messages.success(request, 'Your offer attachment #{0} has been submitted.'.format(instance.pk))
# advise of any errors
else
messages.error('Error(s) encountered during form processing, please review below and re-submit')
return self.render_to_response(context)
html模板的作用如下:
...
<form id='offer_negotiation_form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
{% csrf_token %}
{{ negotiation_bid_form.as_p }}
...
<input type="submit" name="{{ negotiation_bid_form.prefix }}-submit-counter-bid"
title="Submit a counter bid"
value="Counter Bid" />
</form>
...
<form id='offer-attachment-form' class="content-form" action='./' enctype="multipart/form-data" method="post" accept-charset="utf-8">
{% csrf_token %}
{{ offer_attachment_form.as_p }}
<input name="{{ offer_attachment_form.prefix }}-submit" type="submit" value="Submit" />
</form>
...
。。。
{%csrf_令牌%}
{{谈判{投标}形式为{p}
...
...
{%csrf_令牌%}
{{offer_attachment_form.as_p}
...
这有点晚了,但这是我找到的最好的解决方案。为表单名称及其类创建一个查找字典,还必须添加一个属性来标识表单,并且在视图中必须使用form.formlabel
将其作为隐藏字段添加
# form holder
form_holder = {
'majeur': {
'class': FormClass1,
},
'majsoft': {
'class': FormClass2,
},
'tiers1': {
'class': FormClass3,
},
'tiers2': {
'class': FormClass4,
},
'tiers3': {
'class': FormClass5,
},
'tiers4': {
'class': FormClass6,
},
}
for key in form_holder.keys():
# If the key is the same as the formlabel, we should use the posted data
if request.POST.get('formlabel', None) == key:
# Get the form and initate it with the sent data
form = form_holder.get(key).get('class')(
data=request.POST
)
# Validate the form
if form.is_valid():
# Correct data entries
messages.info(request, _(u"Configuration validée."))
if form.save():
# Save succeeded
messages.success(
request,
_(u"Données enregistrées avec succès.")
)
else:
# Save failed
messages.warning(
request,
_(u"Un problème est survenu pendant l'enregistrement "
u"des données, merci de réessayer plus tard.")
)
else:
# Form is not valid, show feedback to the user
messages.error(
request,
_(u"Merci de corriger les erreurs suivantes.")
)
else:
# Just initiate the form without data
form = form_holder.get(key).get('class')(key)()
# Add the attribute for the name
setattr(form, 'formlabel', key)
# Append it to the tempalte variable that will hold all the forms
forms.append(form)
我希望这将在将来有所帮助。以下是处理上述问题的简单方法 在Html模板中,我们将
<form action="/useradd/addnewroute/" method="post" id="login-form">{% csrf_token %}
<!-- add details of form here-->
<form>
<form action="/useradd/addarea/" method="post" id="login-form">{% csrf_token %}
<!-- add details of form here-->
<form>
在URL中
提供所需信息,如
urlpatterns = patterns('',
url(r'^addnewroute/$', views.addnewroute, name='addnewroute'),
url(r'^addarea/', include('usermodules.urls')),
我需要在同一页上独立验证的多个表单。我缺少的关键概念是1)使用表单前缀作为提交按钮名称,2)无边界表单不会触发验证。如果它对其他人有帮助的话,下面是我使用TemplateView的两种表单的简化示例,它基于@adam nelson和@daniel sokolowski的答案和@zeraien()的评论:
#views.py
定义获取表单(请求、表单、前缀):
数据=request.POST如果前缀在request.POST else中则为request.POST无
返回表单CLS(数据,前缀=前缀)
类MyView(TemplateView):
模板名称='mytemplate.html'
def get(自我、请求、*args、**kwargs):
返回self.render_to_响应({'aform':aform(prefix='aform_pre'),'bform':bform(prefix='bform_pre'))
def post(自我、请求、*args、**kwargs):
aform=_get_form(请求,aform,'aform_pre')
bform=_get_form(请求,bform,'bform_pre')
如果aform.is_绑定且aform.is_有效():
#处理表单并呈现响应
elif bform.is_绑定且bform.is_有效()
#处理bform并呈现响应
返回self.render_到_响应({'aform':aform,'bform':bform})
#mytemplate.html
{%csrf_令牌%}
{{aform.as_p}
{{bform.as_p}}
如果您使用基于类的视图和不同的“动作”属性的方法,我的意思是
在两个表单的操作中放置不同的URL。然后您将有两个不同的视图函数来处理这两种不同的表单
您可以使用重载的get\u context\u data
方法轻松处理来自不同表单的错误,例如:
views.py:
class LoginView(FormView):
form_class = AuthFormEdited
success_url = '/'
template_name = 'main/index.html'
def dispatch(self, request, *args, **kwargs):
return super(LoginView, self).dispatch(request, *args, **kwargs)
....
def get_context_data(self, **kwargs):
context = super(LoginView, self).get_context_data(**kwargs)
context['login_view_in_action'] = True
return context
class SignInView(FormView):
form_class = SignInForm
success_url = '/'
template_name = 'main/index.html'
def dispatch(self, request, *args, **kwargs):
return super(SignInView, self).dispatch(request, *args, **kwargs)
.....
def get_context_data(self, **kwargs):
context = super(SignInView, self).get_context_data(**kwargs)
context['login_view_in_action'] = False
return context
模板:
<div class="login-form">
<form action="/login/" method="post" role="form">
{% csrf_token %}
{% if login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
.....
</form>
</div>
<div class="signin-form">
<form action="/registration/" method="post" role="form">
{% csrf_token %}
{% if not login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
....
</form>
</div>
{% block container %}
<div class="container">
<br/>
<form action="{% url 'manager:add_product' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
{{ sub_form.as_p }}
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
{% endblock %}
{%csrf_令牌%}
{%if登录\查看\在\操作%}
{form.non_field_errors%}
{{e}}
×
{%endfor%}
{%endif%}
.....
{%csrf_令牌%}
{%如果未登录\查看\在\操作%}
{form.non_field_errors%}
{{e}}
×
{%endfor%}
{%endif%}
....
想在不使用Django表单的地方分享我的解决方案。
我在一个页面上有多个表单元素,我想使用一个视图来管理来自所有表单的所有POST请求
我所做的是引入了一个不可见的输入标记,这样我就可以向视图传递一个参数来检查提交了哪个表单
<form method="post" id="formOne">
{% csrf_token %}
<input type="hidden" name="form_type" value="formOne">
.....
</form>
.....
<form method="post" id="formTwo">
{% csrf_token %}
<input type="hidden" name="form_type" value="formTwo">
....
</form>
{%csrf_令牌%}
.....
.....
{%csrf_令牌%}
....
views.py
def handlemultipleforms(request, template="handle/multiple_forms.html"):
"""
Handle Multiple <form></form> elements
"""
if request.method == 'POST':
if request.POST.get("form_type") == 'formOne':
#Handle Elements from first Form
elif request.POST.get("form_type") == 'formTwo':
#Handle Elements from second Form
def handlemultipleforms(请求,template=“handle/multipleforms.html”):
"""
处理多个元素
"""
如果request.method==“POST”:
if request.POST.get(“form_type”)=“formOne”:
#从第一个窗体处理元素
elif request.POST.get(“form_type”)=“formTwo”:
#从第二个表单处理元素
查看:
class AddProductView(generic.TemplateView):
template_name = 'manager/add_product.html'
def get(self, request, *args, **kwargs):
form = ProductForm(self.request.GET or None, prefix="sch")
sub_form = ImageForm(self.request.GET or None, prefix="loc")
context = super(AddProductView, self).get_context_data(**kwargs)
context['form'] = form
context['sub_form'] = sub_form
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
form = ProductForm(request.POST, prefix="sch")
sub_form = ImageForm(request.POST, prefix="loc")
...
模板:
<div class="login-form">
<form action="/login/" method="post" role="form">
{% csrf_token %}
{% if login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
.....
</form>
</div>
<div class="signin-form">
<form action="/registration/" method="post" role="form">
{% csrf_token %}
{% if not login_view_in_action %}
{% for e in form.non_field_errors %}
<div class="alert alert-danger alert-dismissable">
{{ e }}
<a class="panel-close close" data-dismiss="alert">×</a>
</div>
{% endfor %}
{% endif %}
....
</form>
</div>
{% block container %}
<div class="container">
<br/>
<form action="{% url 'manager:add_product' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
{{ sub_form.as_p }}
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
{% endblock %}
{%block container%}
{%csrf_令牌%}
{{form.as_p}}
{{sub_form.as_p}}
提交
{%endblock%}
这正是我想要的。这种方法有一个问题,即它验证表单的两个错误。但是效果很好。基于@ybendana:
同样,我们使用is_-bound
检查表单是否能够进行验证。见:
表单实例要么绑定到一组数据,要么解除绑定
- 如果它绑定到一组数据,它就能够验证该数据并将表单呈现为HTML格式,其中的数据显示在HTML中
- 如果未绑定,则无法进行验证(因为vali没有数据)
{% block container %} <div class="container"> <br/> <form action="{% url 'manager:add_product' %}" method="post"> {% csrf_token %} {{ form.as_p }} {{ sub_form.as_p }} <p> <button type="submit">Submit</button> </p> </form> </div> {% endblock %}
if request.method == 'POST': expectedphraseform = ExpectedphraseForm(request.POST) bannedphraseform = BannedphraseForm(request.POST) if expectedphraseform.is_valid(): expectedphraseform.save() return HttpResponse("Success") if bannedphraseform.is_valid(): bannedphraseform.save() return HttpResponse("Success") else: bannedphraseform = BannedphraseForm() expectedphraseform = ExpectedphraseForm() return render(request, 'some.html',{'bannedphraseform':bannedphraseform, 'expectedphraseform':expectedphraseform})
# views.py class MultipleForms(TemplateResponseMixin, ContextMixin, View): form_list = [ # (context_key, formcls, prefix) ("form_a", FormA, "prefix_a"), ("form_b", FormB, "prefix_b"), ("form_c", FormC, "prefix_c"), ... ("form_x", FormX, "prefix_x"), ] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Add blank forms to context with prefixes for context_key, formcls, prefix in self.form_list: context[context_key] = formcls(prefix=prefix) return context def post(self, request, *args, **kwargs): # Get object and context self.object = self.get_object() context = self.get_context_data(object=self.object) # Process forms for context_key, formcls, prefix in self.form_list: if prefix in request.POST: # Get the form object with prefix and pass it the POST data to \ # validate and clean etc. form = formcls(request.POST, prefix=prefix) if form.is_bound: # If the form is bound (i.e. it is capable of validation) \ # check the validation if form.is_valid(): # call the form's save() method or do whatever you \ # want with form.cleaned_data form.save() else: # overwrite context data for this form so that it is \ # returned to the page with validation errors context[context_key] = form # Pass context back to render_to_response() including any invalid forms return self.render_to_response(context)
def create_profile(request): if request.method=='POST': try: biograph = Biography(name=name, email=email, full_name=full_name, slug_name=slug_name, short_bio=short_bio) biograph.save() except: social = SocialMedia(twitter=twitter, instagram=instagram, facebook=facebook, linkedin=linkedin, github=github) social.save()