Django ModelForm: À quoi sert save (commit = False)?

88

Pourquoi utiliserais-je save(commit=False)au lieu de simplement créer un objet de formulaire à partir de la ModelFormsous - classe et de l'exécuter is_valid()pour valider à la fois le formulaire et le modèle?

En d'autres termes, à quoi ça sert save(commit=False)?

Si cela ne vous dérange pas, pourriez-vous fournir des situations hypothétiques où cela pourrait être utile?

sgarza62
la source

Réponses:

110

C'est utile lorsque vous récupérez la plupart de vos données de modèle à partir d'un formulaire, mais que vous devez remplir certains null=Falsechamps avec des données non formelles.

Enregistrer avec commit = False vous donne un objet modèle, vous pouvez ensuite ajouter vos données supplémentaires et les enregistrer.

C'est un bon exemple de cette situation.

Dokkaebi
la source
Mais si cela vous donne un objet modèle, en quoi cela diffère-t-il de l'affectation d'un objet précédemment instancié et de son affectation au ModelForm? (ie form = forms.SampleForm(instance = models.Sample))
OzzyTheGiant
Avez-vous besoin commit=Falsesi vous traitez votre formulaire dans un CBVavec def form_valid? Pouvez-vous simplement utiliser form.instance.[field]pour mettre à jour?
alias51
Allons au 100 :)
dani herrera
40

Voici la réponse ( tirée de la documentation ):

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

La situation la plus courante est d'obtenir l'instance à partir du formulaire mais uniquement «en mémoire», pas dans la base de données. Avant de l'enregistrer, vous souhaitez apporter des modifications:

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

# Save the new instance.
>>> new_author.save()
Dani Herrera
la source
1
Avez-vous besoin commit=Falsesi vous traitez votre formulaire dans un CBVavec def form_valid? Pouvez-vous simplement utiliser form.instance.[field]pour mettre à jour?
alias51
15

À partir de la documentation Django:

Cette méthode save () accepte un argument de mot clé de validation facultatif, qui accepte soit True, soit False. Si vous appelez save () avec commit = False, alors il renverra un objet qui n'a pas encore été enregistré dans la base de données.

Dans ce cas, c'est à vous d'appeler save () sur l'instance de modèle résultante. Ceci est utile si vous souhaitez effectuer un traitement personnalisé sur l'objet avant de l'enregistrer, ou si vous souhaitez utiliser l'une des options d'enregistrement de modèle spécialisées. commit est True par défaut.

Il semble que save (commit = False) crée une instance de modèle, qu'il vous renvoie. Ce qui est bien pour un post-traitement avant de l'enregistrer!

AJRouvoet
la source
10

Comme "vrai exemple", considérez un modèle d'utilisateur où l'adresse e-mail et le nom d'utilisateur sont toujours les mêmes, puis vous pouvez remplacer la méthode d'enregistrement de votre ModelForm comme:

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

Si vous n'avez pas utilisé commit=Falsepour définir le nom d'utilisateur sur l'adresse e-mail, vous devrez soit modifier la méthode d'enregistrement du modèle utilisateur, soit enregistrer l'objet utilisateur deux fois (ce qui duplique une opération de base de données coûteuse.)

Mark Chackerian
la source
Avez-vous besoin commit=Falsesi vous traitez votre formulaire dans un CBVavec def form_valid? Pouvez-vous simplement utiliser form.instance.[field]pour mettre à jour?
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()

voici mon exemple d'utilisation de save (commit = False). Je voulais vérifier quel type de fichier un utilisateur a téléchargé avant de l'enregistrer dans la base de données. Je voulais aussi connaître la date à laquelle il était attaché puisque ce champ n'était pas dans le formulaire.

Kollyn Lund
la source
ceci est un code python que vous ne pouvez pas exécuter dans un extrait de code
Ayoub Benayache