Django ModelForm: ¿Para qué se usa save (commit = False)?

88

¿Por qué usaría en save(commit=False)lugar de simplemente crear un objeto de formulario a partir de la ModelFormsubclase y ejecutarlo is_valid()para validar tanto el formulario como el modelo?

En otras palabras, ¿ save(commit=False)para qué sirve ?

Si no les importa, ¿podrían proporcionar situaciones hipotéticas en las que esto podría ser útil?

sgarza62
fuente

Respuestas:

110

Eso es útil cuando obtiene la mayoría de los datos de su modelo de un formulario, pero necesita completar algunos null=Falsecampos con datos que no son del formulario.

Guardar con commit = False le da un objeto modelo, luego puede agregar sus datos adicionales y guardarlo.

Este es un buen ejemplo de esa situación.

dokkaebi
fuente
Pero luego, si esto le da un objeto modelo, ¿en qué se diferencia de asignar un objeto previamente instanciado y asignarlo al ModelForm? (ie form = forms.SampleForm(instance = models.Sample))
OzzyTheGiant
¿Necesita commit=Falsesi está procesando su formulario en un CBVcon def form_valid? ¿Puedes usar form.instance.[field]para actualizar?
alias51
Vamos al 100 :)
dani herrera
40

Aquí está la respuesta ( de los documentos ):

# 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 situación más común es obtener la instancia del formulario, pero solo "en la memoria", no en la base de datos. Antes de guardarlo, desea realizar algunos cambios:

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

# Save the new instance.
>>> new_author.save()
dani herrera
fuente
1
¿Necesita commit=Falsesi está procesando su formulario en un CBVcon def form_valid? ¿Puedes usar form.instance.[field]para actualizar?
alias51
15

De los documentos de Django:

Este método save () acepta un argumento de palabra clave de confirmación opcional, que acepta True o False. Si llama a save () con commit = False, devolverá un objeto que aún no se ha guardado en la base de datos.

En este caso, depende de usted llamar a save () en la instancia del modelo resultante. Esto es útil si desea realizar un procesamiento personalizado en el objeto antes de guardarlo, o si desea utilizar una de las opciones especializadas para guardar modelos. commit es True por defecto.

Parece que save (commit = False) crea una instancia de modelo, que le devuelve. ¡Lo cual es bueno para un procesamiento posterior antes de guardarlo!

AJRouvoet
fuente
10

Como un "ejemplo real", considere un modelo de usuario donde la dirección de correo electrónico y el nombre de usuario son siempre los mismos, y luego podría sobrescribir el método de guardado de su ModelForm como:

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 no usó commit=Falsepara configurar el nombre de usuario en la dirección de correo electrónico, tendría que modificar el método de guardado del modelo de usuario o guardar el objeto de usuario dos veces (lo que duplica una operación costosa de la base de datos).

Mark Chackerian
fuente
¿Necesita commit=Falsesi está procesando su formulario en un CBVcon def form_valid? ¿Puedes usar form.instance.[field]para actualizar?
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()

aquí está mi ejemplo de cómo usar save (commit = False). Quería comprobar qué tipo de archivo subió un usuario antes de guardarlo en la base de datos. También quería obtener la fecha en que se adjuntó, ya que ese campo no estaba en el formulario.

Kollyn Lund
fuente
este es un código de Python que no puede ejecutar en un fragmento de código
Ayoub Benayache