Django ModelForm: Do czego służy save (commit = False)?

88

Dlaczego miałbym kiedykolwiek używać save(commit=False)zamiast po prostu tworzyć obiekt formularza z ModelFormpodklasy i uruchamiać w is_valid()celu sprawdzenia poprawności zarówno formularza, jak i modelu?

Innymi słowy, do czego służy save(commit=False)?

Jeśli nie masz nic przeciwko, czy moglibyście przedstawić hipotetyczne sytuacje, w których może to być przydatne?

sgarza62
źródło

Odpowiedzi:

110

Jest to przydatne, gdy większość danych modelu uzyskujesz z formularza, ale musisz wypełnić niektóre null=Falsepola danymi spoza formularza.

Zapisanie z commit = False daje ci obiekt modelu, a następnie możesz dodać dodatkowe dane i zapisać je.

To jest dobry przykład takiej sytuacji.

dokkaebi
źródło
Ale jeśli w ten sposób otrzymasz obiekt modelu, czym różni się on od przypisania wcześniej utworzonego obiektu i przypisania go do ModelForm? (tj. form = forms.SampleForm(instance = models.Sample))
OzzyTheGiant
Czy potrzebujesz, commit=Falsejeśli przetwarzasz swój formularz w CBVz def form_valid? Czy możesz po prostu użyć form.instance.[field]aktualizacji?
alias 51
Przejdźmy do 100 :)
dani herrera
40

Oto odpowiedź ( z dokumentów ):

# 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)

Najczęstszą sytuacją jest pobranie instancji z formularza, ale tylko „w pamięci”, a nie w bazie danych. Przed zapisaniem chcesz wprowadzić pewne zmiany:

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

# Save the new instance.
>>> new_author.save()
dani herrera
źródło
1
Czy potrzebujesz, commit=Falsejeśli przetwarzasz swój formularz w CBVz def form_valid? Czy możesz po prostu użyć form.instance.[field]aktualizacji?
alias 51,
15

Z dokumentacji Django:

Ta metoda save () akceptuje opcjonalny argument słowa kluczowego commit, który akceptuje wartość True lub False. Jeśli wywołasz save () z commit = False, zwróci on obiekt, który nie został jeszcze zapisany w bazie danych.

W takim przypadku to do Ciebie należy wywołanie metody save () w wynikowej instancji modelu. Jest to przydatne, jeśli chcesz wykonać niestandardowe przetwarzanie na obiekcie przed zapisaniem go lub jeśli chcesz użyć jednej ze specjalistycznych opcji zapisywania modelu. commit jest domyślnie True.

Wygląda na to, że save (commit = False) tworzy modelową instancję, którą zwraca do Ciebie. Co jest fajne do przetwarzania końcowego przed zapisaniem!

AJRouvoet
źródło
10

Jako „prawdziwy przykład” rozważ model użytkownika, w którym adres e-mail i nazwa użytkownika są zawsze takie same, a następnie możesz nadpisać metodę zapisu swojego ModelForm, na przykład:

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

Jeśli nie commit=Falseustawiłeś nazwy użytkownika na adres e-mail, musiałbyś albo zmodyfikować metodę zapisywania modelu użytkownika, albo dwukrotnie zapisać obiekt użytkownika (co powiela kosztowną operację bazy danych).

Mark Chackerian
źródło
Czy potrzebujesz, commit=Falsejeśli przetwarzasz swój formularz w CBVz def form_valid? Czy możesz po prostu użyć form.instance.[field]aktualizacji?
alias 51,
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()

oto mój przykład użycia save (commit = False). Chciałem sprawdzić, jaki typ pliku przesłał użytkownik przed zapisaniem go w bazie danych. Chciałem też uzyskać datę dołączenia, ponieważ tego pola nie było w formularzu.

Kollyn Lund
źródło
to jest kod Pythona, którego nie można uruchomić we fragmencie kodu
Ayoub Benayache