【问题标题】:Django - form_valid() vs save()Django - form_valid() 与 save()
【发布时间】:2018-12-12 20:16:30
【问题描述】:

在django表单中,为了保存其他数据,我通常使用form_valid(),但我也可以使用formclass的save()方法。

今天我覆盖了save() 而不是form_valid(),但我的manytomanyfield 出现了问题。

使用时,manytomanyfield 的值没有保存,但是当我使用form_valid() 时,它们开始保存。谁能告诉我原因和两者有什么区别,哪种方法最方便,在什么情况下?

这是我对 save() 方法的重写:

class ProductCreateForm(forms.ModelForm):
    sizes = make_ajax_field(ProductCreateModel,'sizes','sizes')
    colours = make_ajax_field(ProductCreateModel,'colours','colours')

    class Meta:
        model = ProductCreateModel

        fields = ('title','category',
                    'regions',)

    def __init__(self,*args,**kwargs):
        self.request = kwargs.pop("request")
        super(ProductCreateForm, self).__init__(*args, **kwargs)

    def save(self):
        product = super(ProductCreateForm, self).save(commit=False)
        user =  self.request.user

        product.location = user.user_location
        product.save()
        return product

当我重写 form_valid() 方法时:

   def get_form_kwargs(self):
       kwargs = super(ProductCreateView,self).get_form_kwargs()
       kwargs.update({'request':self.request})
       return kwargs

   def form_valid(self, form):
       product = form.save(commit=False)
       user =  self.request.user
       form.instance.user = user
       form.instance.location = user.user_location
       form.save()
       return super(ProductCreateView, self).form_valid(form)

sizescoloursregions 是 m2m 字段,正如我在覆盖 save() 时提到的那样,m2m 的值不会被保存,但是当我覆盖 form_valid 时,它们会开始保存。

【问题讨论】:

  • 能否请您发布您的覆盖。另外,您能否解释一下他们开始保存是什么意思。您在数据库中看到它们了吗?它们出现在您的表单上?
  • @scharette 我添加了我的两种方法。

标签: python django django-models django-forms django-views


【解决方案1】:

如果使用commit=False保存表单,则必须调用表单的save_m2m方法来保存多对多数据。请参阅the docs 了解更多信息。

如果您决定使用form_valid 方法,我将更改以下内容:

  • 更新form.save()返回的实例并保存,而不是再次调用form.save()
  • 明确调用form.save_m2m()
  • 返回重定向响应而不是调用super().form_valid()(这将再次保存表单)

把这些放在一起,你会得到:

def form_valid(self, form):
    product = form.save(commit=False)
    product.user =  self.request.user
    product.location.location = user.user_location
    product.save()
    form.save_m2m()
    return redirect('/success-url/')

【讨论】:

  • 还会补充说推荐redirect应该基于选择,因为通用view.form_valid已经返回一个HttpResponseRedirect到success_url。
  • @jackotonye 我已经解释了为什么我建议返回重定向响应 - 如果您调用 super().form_valid() 则表单会再次保存。还有其他方法(例如 response = super(ProductCreateView, self).form_valid(form); form.save_m2m; return response`,但我更喜欢显式返回。
【解决方案2】:

关于 manytomany 的问题,我猜是他们做事的顺序... Form > Admin > Models,当你使用 form_valid 时,他们首先要做的就是检查链中的其他事情,而使用 save 是最后一个,也许可能是因为或其他原因...

最好的方法是始终使用 form_valid 而不是原始保存

form_valid首先检查 Clean 函数是否存在任何原生验证错误或自定义验证,然后才保存您的模型

保存只需保存它而不进行验证,然后使用您的表单进行验证

例子

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise forms.ValidationError(
                    "Did not send for 'help' in the subject despite "
                    "CC'ing yourself."
                )

来源:https://docs.djangoproject.com/en/2.0/ref/forms/validation/

【讨论】:

  • 感谢您的回答,但请不要说form_valid是第一个,当我在这两种方法中编写打印语句时,先执行save()的打印语句然后执行form_valid,请编辑您的回答,不要写猜测。
  • 你知道在 form_valid 里面他可以调用 saves ......但是如果你把 commit=false 保存不会被调用,你会手动调用它......所以是的 form_valid 首先被调用并保存在里面他之后。所以我没有猜测
  • 就像我说的...首先检查是否有效,在里面运行 Clean 然后保存
  • 好吧,你是对的,因为我在 super 之后打印 form_valid save() 方法在 super 中执行,并首先打印 save 语句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-04
  • 2018-04-07
  • 1970-01-01
  • 2019-09-11
  • 2012-02-21
  • 2013-05-12
  • 1970-01-01
相关资源
最近更新 更多