Мастер форм Django: почему метод done () не вызывается после отправки? - PullRequest
0 голосов
/ 29 августа 2018

Я использую 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)])

Шаблоны

add_discount.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_form_horizontal.html

{{ 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 Ответ

0 голосов
/ 29 августа 2018

Метод done() всегда вызывается, если form представлен на последнем шаге is_valid(). Поэтому, если это не так, это должно означать, что ваш form недействителен.

В вашем случае вы скрываете поля, обязательные для вашего DiscountForm1. Таким образом, вы также скрываете ошибку для этих полей. Вы должны сделать их необязательными и проверить в методе clean() формы, заполнены ли соответствующие поля.

...