8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

在Django中处理一个页面上的多个表单的正确方法

Mayah 2月前

140 0

我有一个模板页面需要两个表单。如果我只使用一个表单,那么一切正常,如以下典型示例所示:if request.method == 'POST': form = AuthorForm(request.POST,) if form.is_va...

我有一个模板页面需要两个表单。如果我只使用一个表单,那么一切就都正常了,如以下典型示例所示:

if request.method == 'POST':
    form = AuthorForm(request.POST,)
    if form.is_valid():
        form.save()
        # do something.
else:
    form = AuthorForm()

但是,如果我想使用多个表单,我该如何让视图知道我只提交其中一个表单而不是另一个表单(即它仍然是 request.POST 但我只想处理发生提交的表单)?


这是 基于答案的解决方案,其中 expectedphrase bannedphrase 是不同表单的提交按钮的名称,而 expectedphraseform bannedphraseform 是表单。

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')
帖子版权声明 1、本帖标题:在Django中处理一个页面上的多个表单的正确方法
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Mayah在本站《forms》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您的解决方案是否存在逻辑错误?如果您发布“bannedphrase”,expectedphraseform 将不会被填充。

  • oop 2月前 0 只看Ta
    引用 3

    所有这些答案都很有帮助,但它们没有解决无效表格的问题。当两个表格可能无效时,有人知道如何返回无效表格吗?

  • 我真的很惊讶这些答案都没有引用表单集:\'表单集是在同一页面上处理多个表单的抽象层。\' 请参阅此处的文档

  • 您有以下几种选择:

    1. p1

    2. p2

  • 3) 确定哪个表单是从 POST 数据中的字段名称提交的。如果您的表单没有唯一字段且所有可能的值都不为空,请包含一些隐藏输入。

  • Lii 2月前 0 只看Ta
    引用 7

    如果可能的话,我会避免污染 POST 数据。我建议改为在表单操作 URL 中添加 GET 参数。

  • Yoda 2月前 0 只看Ta
    引用 8

    #1 确实是您最好的选择。您不想用隐藏字段污染您的 POST,也不想将您的视图绑定到您的模板和/或表单。

  • akki 2月前 0 只看Ta
    引用 9

    @meteorainer 如果您使用第一个,是否有办法将错误传递回实例化这些的父视图中的表单,而无需使用消息框架或查询字符串?这个答案似乎最接近,但这里仍然只有一个视图处理两种形式:.com/a/21271659/2532070

  • 供将来参考的方法是这样的。bannedphraseform 是第一种形式,expectedphraseform 是第二种形式。如果第一个被击中,则跳过第二个(在本例中这是一个合理的假设):

    if request.method == 'POST':
        bannedphraseform = BannedPhraseForm(request.POST, prefix='banned')
        if bannedphraseform.is_valid():
            bannedphraseform.save()
    else:
        bannedphraseform = BannedPhraseForm(prefix='banned')
    
    if request.method == 'POST' and not bannedphraseform.is_valid():
        expectedphraseform = ExpectedPhraseForm(request.POST, prefix='expected')
        bannedphraseform = BannedPhraseForm(prefix='banned')
        if expectedphraseform.is_valid():
            expectedphraseform.save()
    
    else:
        expectedphraseform = ExpectedPhraseForm(prefix='expected')
    
  • 这些前缀是个好主意,我们现在就用它们,它们效果很好。但我们仍然必须插入一个隐藏字段来检测提交了哪个表单,因为两个表单都在灯箱中(每个都在单独的灯箱中)。因为我们需要重新打开正确的灯箱,所以我们需要确切知道提交了哪个表单,然后如果第一个表单有任何验证错误,第二个表单将自动获胜,第一个表单将被重置,尽管我们仍然需要显示第一个表单中的错误。只是觉得你应该知道

  • 将此模式扩展到三种表单的情况会不会很笨拙?例如,先检查第一个表单的 is_valid(),然后再检查前两个表单,等等……也许只需让treated = False,当找到兼容的表单时将其更新为True?

  • 我需要在同一页面上独立验证的多个表单。我遗漏的关键概念是 1) 使用表单前缀作为提交按钮名称和 2) 无界表单不会触发验证。如果它对其他人有帮助,以下是我使用 TemplateView 的两个表单 AForm 和 BForm 的简化示例,基于 @adam-nelson 和 @daniel-sokolowski 的回答以及 @zeraien 的评论( https://.com/a/17303480/2680349 ):

    # views.py
    def _get_form(request, formcls, prefix):
        data = request.POST if prefix in request.POST else None
        return formcls(data, prefix=prefix)
    
    class MyView(TemplateView):
        template_name = 'mytemplate.html'
    
        def get(self, request, *args, **kwargs):
            return self.render_to_response({'aform': AForm(prefix='aform_pre'), 'bform': BForm(prefix='bform_pre')})
    
        def post(self, request, *args, **kwargs):
            aform = _get_form(request, AForm, 'aform_pre')
            bform = _get_form(request, BForm, 'bform_pre')
            if aform.is_bound and aform.is_valid():
                # Process aform and render response
            elif bform.is_bound and bform.is_valid():
                # Process bform and render response
            return self.render_to_response({'aform': aform, 'bform': bform})
    
    # mytemplate.html
    <form action="" method="post">
        {% csrf_token %}
        {{ aform.as_p }}
        <input type="submit" name="{{aform.prefix}}" value="Submit" />
        {{ bform.as_p }}
        <input type="submit" name="{{bform.prefix}}" value="Submit" />
    </form>
    
  • 我非常喜欢这个解决方案。有一个问题:为什么 _get_form() 不是 MyView 类的方法?

  • @AndréTerra 绝对可以,尽管您可能希望将它放在从 TemplateView 继承的通用类中,以便可以在其他视图中重用它。

  • 这是一个很好的解决方案。我需要更改 __get_form 的一行才能使其正常工作:data = request.POST if prefix in next(iter(request.POST.keys())) else None 否则不起作用。

  • 使用单个

    tag like this means required fields are required globally when they should be per-form depending on which submit button was clicked. Splitting into two
    tags (with the same action) works.
  • 想要分享我的解决方案,其中没有使用 Django Forms。我在单个页面上有多个表单元素,我想使用单个视图来管理来自所有表单的所有 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>
    

    视图.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
    
  • 虽然这可能不是最优雅和可扩展的解决方案,但它绝对非常简单且易于实现。而且是迄今为止速度最快的。我已经在自定义 CBV 中实现了它,效果非常好。好主意!

  • Django 的基于类的视图提供了一个通用的 FormView,但出于所有意图和目的,它被设计为仅处理一种表单。

    使用 Django 的通用视图处理具有相同目标操作 URL 的多个表单的一种方法是扩展“TemplateView”,如下所示;我经常使用这种方法,因此我已将其制成 Eclipse IDE 模板。

    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>
    
    ...
    
返回
作者最近主题: