ChatGPT解决这个技术问题 Extra ChatGPT

Django ModelForm:save(commit=False) 有什么用?

为什么我会使用 save(commit=False) 而不是仅从 ModelForm 子类创建一个表单对象并运行 is_valid() 来验证表单和模型?

换句话说,save(commit=False) 是干什么用的?

如果您不介意,你们能否提供可能有用的假设情况?


d
dokkaebi

这在您从表单中获取大部分模型数据时很有用,但您需要使用非表单数据填充一些 null=False 字段。

使用 commit=False 保存会得到一个模型对象,然后您可以添加额外的数据并保存它。

This is a good example of that situation.

这是documentation on the save method。请注意,如果您的表单包含多对多字段,您还需要在保存模型实例后调用 form.save_m2m()


但是,如果这为您提供了一个模型对象,那么它与分配先前实例化的对象并将其分配给 ModelForm 有何不同? (即form = forms.SampleForm(instance = models.Sample)
如果您在带有 def form_validCBV 中处理表单,是否需要 commit=False?你可以只使用 form.instance.[field] 来更新吗?
让我们去 100 :)
是的,但是:你能解释一下为什么它被称为 Django Antipatterns django-antipatterns.com/antipattern/…。我看到这种方法到处都是,但找不到好的替代方法。谢谢你!
感谢您的评论,@Carlo。 Django 文档仍然推荐此答案中的方法(我添加了一个链接),但看起来 django-antipatterns 推荐的解决方案也可以。
d
dani herrera

这是答案(from docs):

# Create a form instance with POST data.
>>> f = AuthorForm(request.POST)

# Create, but don't save the new author instance.
>>> new_author = f.save(commit=False)

最常见的情况是从表单中获取实例,但仅“在内存中”,而不是在数据库中。在保存之前,您需要进行一些更改:

# Modify the author in some way.
>>> new_author.some_field = 'some_value'

# Save the new instance.
>>> new_author.save()

如果您在带有 def form_validCBV 中处理表单,是否需要 commit=False?你可以只使用 form.instance.[field] 来更新吗?
M
Muhammmed Nihad

来自 Django 文档:

这个 save() 方法接受一个可选的 commit 关键字参数,它接受 True 或 False。如果您使用 commit=False 调用 save(),那么它将返回一个尚未保存到数据库的对象。在这种情况下,您可以在生成的模型实例上调用 save() 。如果您想在保存对象之前对其进行自定义处理,或者如果您想使用专门的模型保存选项之一,这将非常有用。提交默认为真。

似乎 save(commit=False) 确实创建了一个模型实例,它会返回给您。在实际保存之前,这对于一些后期处理来说是很好的!


M
Mark Chackerian

作为“真实示例”,考虑一个用户模型,其中电子邮件地址和用户名始终相同,然后您可以覆盖 ModelForm 的保存方法,例如:

class UserForm(forms.ModelForm):
    ...
    def save(self):
        # Sets username to email before saving
        user = super(UserForm, self).save(commit=False)
        user.username = user.email
        user.save()
        return user

如果您没有使用 commit=False 将用户名设置为电子邮件地址,那么您要么必须修改用户模型的保存方法,要么将用户对象保存两次(这会重复昂贵的数据库操作。)


如果您在带有 def form_validCBV 中处理表单,是否需要 commit=False?你可以只使用 form.instance.[field] 来更新吗?
M
Muhammmed Nihad

我理解的基本内容是它从“表单”实例变为视图中的特定“模型”实例。

假设我想在 StackOverflow 中发布这样的答案。代码将是这样的:

# Create a form instance with POST data.
>>> form_data = AnswerForm(request.POST)

# Create, but don't save the new answer instance.
>>> Answer = form_data.save(commit=False)

因此,现在我们必须添加此答案的所有者并将其保存在我们的数据库中的视图页面中,如下所示:

>>> Answer.owner = request.user

>>> Answer.save()

所以像这样,我们可以在视图页面中添加这个答案的所有者,我们不能像 form_data.owner = request.user 那样做,也不能在表单类中做。

所以基本上,它从“表单”实例变为“模型”实例,然后让您修改数据并保存它。


K
Kollyn Lund
            form = AddAttachmentForm(request.POST, request.FILES)
            if form.is_valid():
                attachment = form.save(commit=False)
                attachment.user = student
                attachment.attacher = self.request.user
                attachment.date_attached = timezone.now()
                attachment.competency = competency
                attachment.filename = request.FILES['attachment'].name
                if attachment.filename.lower().endswith(('.png','jpg','jpeg','.ai','.bmp','.gif','.ico','.psd','.svg','.tiff','.tif')):
                    attachment.file_type = "image"
                if attachment.filename.lower().endswith(('.mp4','.mov','.3g2','.avi','.flv','.h264','.m4v','.mpg','.mpeg','.wmv')):
                    attachment.file_type = "video"
                if attachment.filename.lower().endswith(('.aif','.cda','.mid','.midi','.mp3','.mpa','.ogg','.wav','.wma','.wpl')):
                    attachment.file_type = "audio"
                if attachment.filename.lower().endswith(('.csv','.dif','.ods','.xls','.tsv','.dat','.db','.xml','.xlsx','.xlr')):
                    attachment.file_type = "spreasheet"
                if attachment.filename.lower().endswith(('.doc','.pdf','.rtf','.txt')):
                    attachment.file_type = "text"
                attachment.save()

这是我使用 save(commit=False) 的示例。我想在将其保存到数据库之前检查用户上传的文件类型。我还想获取它的附加日期,因为该字段不在表单中。


这是一个 python 代码,你不能在代码片段中运行它
S
Shubham Sarda

简单来说,这里我们更新表单对象并让他们知道现在不要将值保存在数据库中,我们可能会使用实例更改一些输入,然后使用 .save() 将所有值保存在数据库中。

这使我们可以灵活地从 HTML 表单中获取所有值并根据我们的要求对其进行自定义,然后保存实例。