130 votes

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

Pourquoi est-ce que j'utiliserais save(commit=False) au lieu de simplement créer un objet de formulaire à partir de la ModelForm et en exécutant is_valid() pour valider à la fois le formulaire et le modèle ?

En d'autres termes, ce qui est save(commit=False) pour ?

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

154voto

dokkaebi Points 4464

C'est utile lorsque vous obtenez la plupart des données de votre modèle à partir d'un formulaire, mais que vous avez besoin de remplir certains champs de données. null=False avec des données non formelles.

Économiser avec commit=False vous donne un objet modèle, vous pouvez alors ajouter vos données supplémentaires et les sauvegarder.

C'est un bon exemple de cette situation.

57voto

danihp Points 15682

Voici la réponse ( à partir 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 seulement 'en mémoire', pas dans la base de données. Avant de la sauvegarder, vous voulez faire quelques changements :

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

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

24voto

A.J.Rouvoet Points 1084

Extrait de la documentation de Django :

Cette méthode save() accepte un argument facultatif de mot-clé commit, qui accepte soit True soit False. Si vous appelez save() avec commit=False , alors il retournera 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 le sauvegarder, ou si vous voulez utiliser l'une des options spécialisées de sauvegarde du modèle. 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 pratique pour un post-traitement avant de l'enregistrer !

13voto

Mark Chackerian Points 1562

Comme "exemple réel", considérez un modèle d'utilisateur où l'adresse e-mail et le nom d'utilisateur sont toujours les mêmes, et alors vous pourriez écraser la méthode de sauvegarde 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=False pour remplacer le nom d'utilisateur par l'adresse électronique, il faudrait soit modifier la méthode d'enregistrement du modèle utilisateur, soit enregistrer deux fois l'objet utilisateur (ce qui duplique une opération coûteuse de la base de données).

2voto

Kollyn Lund Points 15
            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 avait téléchargé avant de le sauvegarder dans la base de données. Je voulais également obtenir la date à laquelle il a été joint puisque ce champ n'était pas dans le formulaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X