Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Django中一页处理多个表单的正确方法_Python_Django_Forms - Fatal编程技术网

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')

您有几个选择:

  • 在两个表单的操作中放置不同的URL。然后您将有两个不同的视图函数来处理这两种不同的表单

  • 从POST数据中读取提交按钮值。您可以判断单击了哪个提交按钮:


  • 未来参考的方法是这样的。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()