1.save() and delete()
save() issues an INSERT or UPDATE (Django decides which based on whether the instance's primary key is already set), and delete() issues a DELETE, removing the row but leaving the Python instance alive in memory with its pk reset to None. Neither one runs full_clean() — save() will happily write invalid data to the database unless something else validates first.
Key features
- save() INSERTs if the instance has no pk set yet (or the pk's field has a default not yet saved), UPDATEs otherwise — Django decides automatically
- save() does NOT call full_clean() or clean() — invalid data (violating a choices= list, a custom clean() rule, etc.) can be saved without error
- delete() removes the database row but the Python object still exists afterward, with its primary key set back to None
- delete() returns a tuple: (total objects deleted, {model_label: count}) — because CASCADE can delete related objects in the same call
- save(update_fields=[...]) restricts the UPDATE to only the named fields — auto_now fields NOT listed in update_fields are not touched
save() vs delete()
- Code → Model instance: order.status = "NOT_A_REAL_STATUS"
- Code → Model instance: order.save()
- Model instance → Database: INSERT/UPDATE — no validation ran
- Database → Code: succeeds — invalid data now stored
Command
order.save() # INSERT or UPDATE, decided automatically
order.save(update_fields=["status"]) # UPDATE only this column
order.delete() # (count, {label: count})save() decides INSERT vs UPDATE automatically and never validates on its own — call full_clean() explicitly first if the write path skips ModelForm. delete() removes the row but the Python object survives, pk reset to None.