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


88

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

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

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

Ответы:


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) действительно создает экземпляр модели, который возвращает вам. Это удобно для пост-обработки перед фактическим сохранением!


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, вы не можете запустить его во фрагменте кода
Аюб Беньяче
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.