Django 在 UpdateView 中处理 2 个表单 - form_valid 不起作用(说无效) - Post 有效吗?

Django handle 2 forms in UpdateView - form_valid doesn't work (says invalid) - Post works?

我有一个应用程序,我将 inline_formset 放在对象表单的模板中。表单集适用于所有相关对象。 'main object'是一个GrowthPlan,相关对象是Response个对象。

当我单击 'save' 时,所有表单集对象 (Response) 都正确保存,没有问题。

但是,主要对象 (GrowthPlan) 没有保存。

正在调用 form_invalid(self): 方法(我在终端中看到我的打印消息)但没有与表单相关的错误。

form_valid(self): 方法从未被调用。

如果我在 post 方法中保存表单,它会按预期保存。但是因为这是一个 UpdateView 我想用 form_validform_invalid 来处理它;或者这是错误的方法吗?

UpdateView 看起来像这样:

class GrowthPlanUpdateView(
    LoginRequiredMixin, UserIsObserverOrObserveeMixin, UpdateView
):

    model = GrowthPlan
    template_name = "commonground/growthplan_form.html"
    form_class = GrowthPlanForm
    pk_url_kwarg = "growthplan_id"

    def get_object(self):
        return get_object_or_404(GrowthPlan, pk=self.kwargs["growthplan_id"])

    def post(self, request, *args, **kwargs):
        self.object = get_object_or_404(
            GrowthPlan, pk=self.kwargs["growthplan_id"]
        )
        regular_form = GrowthPlanForm(
            request.POST or None, instance=self.object
        )
        # IF I UNCOMMENT THIS - THE FORM SAVES APPROPRIATELY
        #if regular_form.is_valid():
        #   # The form saves if I put this line here
        #   # But the form does not not get to form_valid 
        #   regular_form.save()
        # Handle saving the related formsets here
        response_formset = ResponseInlineFormset(
            request.POST or None,
            prefix="response_formset",
            instance=self.object,
        )
        if response_formset.is_valid():
            for formset_form in response_formset:
                if formset_form.is_valid():
                    # This works
                    formset_form.save()
        return super().post(request, *args, **kwargs)

    def get_form(self):
        return self.form_class(instance=self.object)

    def form_invalid(self, form):
        print("form is invalid")
        # THERE ARE NO ERRORS SHOWING HERE - BUT I SEE MY PRINT STATEMENT
        print(form.errors)
        return super().form_invalid(form)

    def form_valid(self, form):
        # THIS IS NEVER CALLED
        print("getting to form_valid")
        form.save()
        messages.add_message(
            self.request, messages.SUCCESS, "Changes were saved!"
        )
        return super().form_valid(form)

    def get_success_url(self):
        user_id = self.kwargs["user_id"]
        summative_id = self.kwargs["summative_id"]
        evaluation = Evaluation.objects.get(id=self.kwargs["evaluation_id"])
        growthplan = evaluation.growthplan
        return reverse(
            "commonground:growthplan_detail",
            kwargs={
                "user_id": user_id,
                "summative_id": summative_id,
                "evaluation_id": evaluation.id,
                "growthplan_id": growthplan.id,
            },
        )

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        summative = get_object_or_404(
            Summative, pk=self.kwargs["summative_id"]
        )
        if self.request.user != summative.employee:
            context["user_is_observer"] = True
        if self.request.user == summative.employee:
            context["user_is_observer"] = False
        context["employee"] = summative.employee
        try:
            context[
                "employee_information"
            ] = EmployeePayInformation.objects.get(user=summative.employee)
        except EmployeePayInformation.DoesNotExist:
            context["employee_information"] = None
        except EmployeePayInformation.MultipleObjectsReturned:
            # TODO: Log error
            context["employee_information"] = None
        context["response_formset"] = ResponseInlineFormset(
            prefix="response_formset", instance=self.object
        )
        context["growthplan_is_complete"] = False
        if self.object.is_complete:
            context["growthplan_is_complete"] = True
        return context

我的表单 HTML 如下所示:

    <form method="post" novalidate>
        {% csrf_token %}
        {{ form.as_p }}
        {{ response_formset.management_form }}
        {{ formset.management_form }}
        {% for formset_form in response_formset.forms %} 
            {{ formset_form.as_p }}
        {% endfor %}
        <button type="submit" class="btn btn-primary"><i class="fal fa-clipboard-check"></i> Update Growth Plan</button>
    </form>

forms.py 表格如下所示:

class GrowthPlanForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(GrowthPlanForm, self).__init__(*args, **kwargs)

    class Meta:
        model = GrowthPlan
        fields = "__all__"

        widgets = {
            "updated_by": forms.HiddenInput(),
            "evaluation": forms.HiddenInput(),
            "created_by": forms.HiddenInput(),
            "initial_date": DatePickerInput(attrs={"class": "form-control"}),
            "mid_date": DatePickerInput(attrs={"class": "form-control"}),
            "final_date": DatePickerInput(attrs={"class": "form-control"}),
            "expected_growth": forms.TextInput(
                attrs={"class": "form-control"}
            ),
            "actual_growth": forms.TextInput(attrs={"class": "form-control"}),
        }


class ResponseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(ResponseForm, self).__init__(*args, **kwargs)
        self.fields["question"].queryset = Question.objects.filter(
            id=self.instance.question.id
        )
        self.fields["question"].empty_label = None

    class Meta:
        model = Response
        fields = "__all__"
        widgets = {
            "user": forms.HiddenInput(),
            "growthplan": forms.HiddenInput(),
            "question": forms.HiddenInput(),
            "comment": forms.Textarea(attrs={"class": "form-control"}),
        }

    def clean(self):
        cleaned_data = super().clean()
        comment = cleaned_data.get("comment")
        growthplan = cleaned_data.get("growthplan")
        if growthplan.is_complete and not comment:
            # The comment is required because it should be complete
            self.add_error(
                "comment",
                """
                You must enter a comment before the Growth Plan can be 
                completed.
                """,
            )


ResponseInlineFormset = inlineformset_factory(
    GrowthPlan,
    Response,
    fields=("question", "comment", "user", "growthplan"),
    can_delete=False,
    extra=0,
    form=ResponseForm,
)

我是否应该在 post 方法中处理此问题并忽略 form_validform_invalid 方法?

我应该使用不同的 CBV 吗?

为什么在表单数据实际有效时出现 form_invalid()

我摸不着头脑 - 任何见解都将受到赞赏!

对于它的价值 - 如果我从 GrowthPlanUpdateView 中删除 get_form 覆盖,它会按预期工作并且表格现在按预期标记为 valid/invalid。