Django动态表单集更新视图未更新。

huangapple go评论90阅读模式
英文:

Django Dynamic Formset UpdateView Not Updating

问题

我使用了这个教程成功地设置了一个使用Django的动态内联表单集的功能。CreateView工作得很好,但我无法让UpdateView实际更新相关字段。没有抛出错误,但项目不会更新。我认为我已经将错误隔离到form_valid函数中。代码如下。感谢任何帮助。

class ApplicantCreate(CreateView):
    model = Applicant
    success_message = 'Your application was submitted successfully.'
    form_class = forms.ApplicantForm
    template_name = 'careers/add_applicant.html'
    success_url = reverse_lazy('careers:thanks')

    # ... 省略其他代码 ...

class ApplicantUpdate(SuccessMessageMixin, LoginRequiredMixin, GroupRequiredMixin, UpdateView):
    group_required = ['careers-admin', 'careers']
    model = Applicant
    success_message = '%(first_name)s %(last_name)s was updated successfully.'
    form_class = forms.ApplicantUpdateForm
    template_name = 'careers/edit_applicant.html'

    # ... 省略其他代码 ...

<details>
<summary>英文:</summary>

I used [this][1] tutorial to successfully set up a dynamic inline formset using Django. The CreateView works great, but I cannot get the UpdateView to actually update the related fields. There are no errors thrown, but the items will not update. I believe I have isolated the error to the form_valid function. The code is as follows. Thank you for any assistance.

    class ApplicantCreate(CreateView):
        model = Applicant
        success_message = &#39;Your application was submitted successfully.&#39;
        form_class = forms.ApplicantForm
        template_name = &#39;careers/add_applicant.html&#39;
        success_url = reverse_lazy(&#39;careers:thanks&#39;)

        def get_context_data(self, **kwargs):
            data = super(ApplicantCreate, self).get_context_data(**kwargs)
            positions = super(ApplicantCreate, self).get_context_data(**kwargs)
            if self.request.POST:
                data[&#39;employer&#39;] = forms.ApplicantEmployerFormSet(
                                        self.request.POST,
                                        prefix=&#39;employer&#39;)
                data[&#39;education&#39;] = forms.ApplicantEducationFormSet(
                                         self.request.POST,
                                         prefix=&#39;education&#39;)
            else:
                data[&#39;employer&#39;] = forms.ApplicantEmployerFormSet(prefix=&#39;employer&#39;)
                data[&#39;education&#39;] = forms.ApplicantEducationFormSet(prefix=&#39;education&#39;)
            return data
            context[&#39;unfilled_positions&#39;] = Position.objects.filter(filled=False)
            return positions

        def form_valid(self, form):
            context = self.get_context_data()
            employer = context[&#39;employer&#39;]
            education = context[&#39;education&#39;]
            with transaction.atomic():
                form.instance.created_by = self.request.user
                self.object = form.save()
                if employer.is_valid():
                    employer.instance = self.object
                    employer.save()
                if education.is_valid():
                    education.instance = self.object
                    education.save()
            return super(ApplicantCreate, self).form_valid(form)

        def get_success_url(self):
            return reverse_lazy(&#39;careers:thanks&#39;)

    class ApplicantUpdate(SuccessMessageMixin,LoginRequiredMixin,GroupRequiredMixin,UpdateView):
        group_required = [u&#39;careers-admin&#39;,u&#39;careers&#39;]
        model = Applicant
        success_message = &#39;%(first_name)s %(last_name)s was updated successfully.&#39;
        form_class = forms.ApplicantUpdateForm
        template_name = &#39;careers/edit_applicant.html&#39;

        def get_context_data(self, **kwargs):
            data = super(ApplicantUpdate, self).get_context_data(**kwargs)
            positions = super(ApplicantUpdate, self).get_context_data(**kwargs)
            if self.request.POST:
                data[&#39;employer&#39;] = forms.ApplicantEmployerFormSet(
                                        self.request.POST,
                                        instance=self.object,
                                        prefix=&#39;employer&#39;)
                data[&#39;education&#39;] = forms.ApplicantEducationFormSet(
                                        self.request.POST,
                                        instance=self.object,
                                        prefix=&#39;education&#39;)
            else:
                data[&#39;employer&#39;] = forms.ApplicantEmployerFormSet(
                                        instance=self.object,
                                        prefix=&#39;employer&#39;)
                data[&#39;education&#39;] = forms.ApplicantEducationFormSet(
                                        instance=self.object,
                                        prefix=&#39;education&#39;)
            return data
            context[&#39;unfilled_positions&#39;] = Position.objects.filter(filled=False)
            return positions

        def form_valid(self, form):
            context = self.get_context_data()
            employer = context[&#39;employer&#39;]
            education = context[&#39;education&#39;]
            with transaction.atomic():
                form.instance.created_by = self.request.user
                self.object = form.save()
                if employer.is_valid():
                    employer.instance = self.object
                    employer.save()
                if education.is_valid():
                    education.instance = self.object
                    education.save()
            return super(ApplicantUpdate, self).form_valid(form)

        def get_success_url(self):
            return reverse_lazy(&#39;careers:applicant_detail&#39;,kwargs={&#39;pk&#39;: self.object.pk})


  [1]: https://dev.to/zxenia/django-inline-formsets-with-class-based-views-and-crispy-forms-14o6

</details>


# 答案1
**得分**: 3

以下是您要翻译的内容:

这不是一篇好的博客文章,因为如果内联表单中的任何一个无效,就不会显示任何错误。作为用户,我不希望视图只是悄悄地忽略内联表单中的错误,成功保存我的主要实例,而不报告这些错误。

请注意,我不知道错误是什么,也许这只是与管理表单有关的问题。但无论如何,应在实际保存主对象之前处理表单集错误。

一般来说,如果您需要编写一个包含多个表单(包括表单集)的视图,最好使用函数型视图或 `View`,在其中编写 `get` 和 `post`,而不是试图将其强制转换为泛型类视图,泛型类视图不适用于此。

```python
def multiple_forms_view(request, object_id):
    # 如果这是一个POST请求,我们需要处理表单数据
    obj = get_object_or_404(MyModel, pk=object_id)
    if request.method == 'POST':
        # 创建一个表单实例并使用请求中的数据填充它:
        form = MyForm(request.POST, instance=obj)
        formset = MyFormSet(request.POST, instance=obj, ...)
        # 检查是否有效:
        if form.is_valid() and formset.is_valid():
            # 根据需要处理表单.cleaned_data中的数据
            # ...
            # 重定向到新的URL:
            return HttpResponseRedirect('/thanks/')

    # 如果是GET(或其他任何方法),我们将创建一个空白表单
    else:
        form = MyForm(instance=obj)
        formset = MyFormSet(instance=obj, ...)

    return render(request, 'name.html', {'form': form, 'formset': formset})

这样,您的模板可以渲染每个表单的错误,包括表单集中的错误。如前所述,您也可以在 View 中执行此操作(以便混合视图有效),只需编写 getpost 方法并返回与上述函数型视图相同的内容。

英文:

This is not a good blog post, because no errors are shown if any of the inline forms aren't valid. As a user, I wouldn't expect the view to just silently ignore errors in the inline forms, saving my main instance successfully and not reporting back those errors.

Note that I don't know what the errors are, maybe it's just an issue with the management form. But in any case, formset errors should be handled before the main object is actually saved.

In general, if you need to write a view with multiple forms (including a formset), it's better to use a function-based view or a View where you write the get and post than trying to force this into a generic class-based view, which is not meant for this.

def multiple_forms_view(request, object_id):
    # if this is a POST request we need to process the form data
    obj = get_object_or_404(MyModel, pk=object_id)
    if request.method == &#39;POST&#39;:
        # create a form instance and populate it with data from the request:
        form = MyForm(request.POST, instance=obj)
        formset = MyFormSet(request.POST, instance=obj, ...)
        # check whether it&#39;s valid:
        if form.is_valid() and formset.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect(&#39;/thanks/&#39;)

    # if a GET (or any other method) we&#39;ll create a blank form
    else:
        form = MyForm(instance=obj)
        formset = MyFormSet(instance=obj, ...)

    return render(request, &#39;name.html&#39;, {&#39;form&#39;: form, &#39;formset&#39;: formset})

That way your template can render the errors of each form, including those in the formset. As mentioned before, you could also do this in a View (so your mixins will work), just write the get and post methods and return the same as in the function-based view above.

huangapple
  • 本文由 发表于 2020年1月7日 01:55:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/59616742.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定