代码之家  ›  专栏  ›  技术社区  ›  David Dahan

Django表单向导:提交后为什么不调用done()方法?

  •  0
  • David Dahan  · 技术社区  · 6 年前

    SessionWizardView done() 方法从未被调用。相反,在发布表单后,在最后一步中,我可以看到 POST HTTP 200 在我的服务器上,但这不起作用。 这个 get_form()

    我怀疑这是一个分散注意力的错误,因为我对另一个视图有完全相同的逻辑,而且效果很好。

    下面是全部代码。

    景色

    class DiscountsCreateView(PermissionRequiredCanHandleProducts,
                          ModelInContextMixin,
                          RestaurantMixin, SubSectionDiscounts,
                          SessionWizardView):
        """ Wizard view to create a discount in 2 steps """
    
        model = Discount  # used for model context
        form_list = [DiscountForm0, DiscountForm1]
        template_name = "discounts/discount_add.html"
    
        def get_form(self, step=None, data=None, files=None):
            form = super().get_form(step, data, files)
    
            if step is None:
                step = self.steps.current
    
            # step0 - name, kind, tax_rate
            # => nothing special to do, always the same form
    
            # step1 - specific fields related to the chosen kind
            if step == '1':
                step0_data = self.storage.get_step_data('0')
                kind = step0_data['0-kind']
                # combo => combo, combo_unit_price
                if kind == Discount.COMBO:
                    form.fields['combo'].queryset = Combo.objects.restaurant(self.restaurant)
                    # NOTE : this is not a scalable way to show/hide fields (exponential)
                    form.fields['rebate_amount'].widget = forms.HiddenInput()
                elif kind == Discount.REBATE:
                    form.fields['combo'].widget = forms.HiddenInput()
                    form.fields['combo_unit_price'].widget = forms.HiddenInput()
    
            return form
    
        def done(self, form_list, **kwargs):
            data = [form.cleaned_data for form in form_list]
            try:
                Discount.objects.create(
                    name=data[0]['name'],
                    kind=data[0]['kind'],
                    tax_rate=data[0]['tax_rate'],
                    rebate_amount=data[1]['rebate_amount'],
                    combo=data[1]['combo'],
                    combo_unit_price=data[1]['combo_unit_price']
                )
            except Exception as e:
                messages.add_message(self.request, messages.ERROR, MSG_DISCOUNT_ADD_KO.format(e))
            else:
                messages.add_message(self.request, messages.SUCCESS, MSG_DISCOUNT_ADD_OK)
    
            return redirect(reverse('bo:discount-list'))
    

    class DiscountForm0(forms.Form):
        name = forms.CharField(
            label=verbose_display(Discount, 'name'))
        kind = forms.ChoiceField(
            label=verbose_display(Discount, 'kind'),
            choices=Discount.KIND_CHOICES)
        tax_rate = forms.ModelChoiceField(
            label=verbose_display(Discount, 'tax_rate'),
            queryset=TaxRate.objects.all())
    
    
    class DiscountForm1(forms.Form):
        """
        Contains all the specific fields for all discount kinds.
        The goal is to only show the fields related to the right discount kind
        """
    
        # For REBATE kind only
        rebate_amount = forms.DecimalField(
            label=verbose_display(Discount, 'rebate_amount'),
            validators=[MaxValueValidator(0)])
    
        # For COMBO kind only
        combo = forms.ModelChoiceField(
            label=verbose_display(Discount, 'combo'),
            queryset=Combo.objects.none()) 
        combo_unit_price = forms.DecimalField(
            label=verbose_display(Discount, 'combo_unit_price'),
            validators=[MinValueValidator(0)])
    

    添加_折扣.html

    {% extends "base_dashboard.html" %}
    {% load verbose_name %}
    
    {% block dashboard_title %}
        Créer une {% model_name model %} : étape {{ wizard.steps.step1 }} / {{ wizard.steps.count }}
    {% endblock dashboard_title %}
    
    {% block dashboard_content %}
    
        <form action='' method='post' novalidate>
            {% csrf_token %}
            {% include 'includes/_wizard_form_horizontal.html' with wizard=wizard %}
        </form>
    
    {% endblock dashboard_content %}
    

    {{ wizard.management_form }}
    {% if wizard.form.forms %}
        {{ wizard.form.management_form }}
        {% for form in wizard.form.forms %}
            {% include 'includes/_form_horizontal.html' with form=form %}
        {% endfor %}
    {% else %}
        {% include 'includes/_form_horizontal.html' with form=wizard.form %}
    {% endif %}
    
    
    {% if wizard.steps.prev %}
        <button class="btn btn-primary" name="wizard_goto_step" type="submit"
                value="{{ wizard.steps.prev }}">
            &laquo; étape précédente
        </button>
    {% endif %}
    <input type="submit" class="btn btn-primary" value="étape suivante &raquo;"/>
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   dirkgroten    6 年前

    这个 done() 如果 form 在最后一步中提交 is_valid() . 所以如果不是,那一定是你的错 无效。

    DiscountForm1 . 所以你也隐藏了这些字段的错误。你应该让它们成为可选的,并检查表单的 clean() 方法(如果已填充适当的字段)。

    推荐文章