Django ModelForm: для чего используется save (commit = False)?

88

Зачем мне использовать save(commit=False)вместо простого создания объекта формы из ModelFormподкласса и запуска is_valid()для проверки формы и модели?

Другими словами, для чего save(commit=False)?

Если вы не возражаете, не могли бы вы представить гипотетические ситуации, в которых это могло бы быть полезно?

sgarza62
источник

Ответы:

110

Это полезно, когда вы получаете большую часть данных модели из формы, но вам нужно заполнить некоторые null=Falseполя данными, не относящимися к форме.

Сохранение с помощью commit = False дает вам объект модели, затем вы можете добавить свои дополнительные данные и сохранить их.

Это хороший пример такой ситуации.

Доккаеби
источник
Но если это дает вам объект модели, чем он отличается от назначения ранее созданного объекта и присвоения его ModelForm? (ie form = forms.SampleForm(instance = models.Sample))
OzzyTheGiant
Вам нужно, commit=Falseесли вы обрабатываете свою форму в CBVс def form_valid? Можно просто использовать form.instance.[field]для обновления?
alias51,
Поехали на 100 :)
дани херрера
40

Вот ответ ( из документов ):

# 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()
Дани Эррера
источник
1
Вам нужно, commit=Falseесли вы обрабатываете свою форму в CBVс def form_valid? Можно просто использовать form.instance.[field]для обновления?
alias51,
15

Из документов Django:

Этот метод save () принимает необязательный аргумент ключевого слова фиксации, который принимает либо True, либо False. Если вы вызовете save () с commit = False, он вернет объект, который еще не был сохранен в базе данных.

В этом случае вы должны вызвать save () для полученного экземпляра модели. Это полезно, если вы хотите выполнить индивидуальную обработку объекта перед его сохранением или если вы хотите использовать одну из специальных опций сохранения модели. commit по умолчанию имеет значение True.

Кажется, что save (commit = False) действительно создает экземпляр модели, который возвращает вам. Это удобно для пост-обработки перед фактическим сохранением!

AJRouvoet
источник
10

В качестве «реального примера» рассмотрим модель пользователя, в которой адрес электронной почты и имя пользователя всегда одинаковы, а затем вы можете перезаписать метод сохранения 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для установки имени пользователя адрес электронной почты, вам пришлось бы либо изменить метод сохранения модели пользователя, либо дважды сохранить объект пользователя (что дублирует дорогостоящую операцию с базой данных).

Марк Чакериан
источник
Вам нужно, commit=Falseесли вы обрабатываете свою форму в CBVс def form_valid? Можно просто использовать form.instance.[field]для обновления?
alias51,
1
            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, вы не можете запустить его во фрагменте кода
Аюб Беньяче