save() and delete()
coreintermediatesave() 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.
Think of it as
save() is a raw persistence operation, not a validated one — the model layer trusts you meant what you set on the instance and writes it, the same way a plain SQL INSERT/UPDATE would. Django deliberately keeps validation (full_clean()) as a SEPARATE, explicit step rather than baking it into save(), because plenty of legitimate code paths (data migrations, bulk imports, internal scripts) need to write data without paying the cost — or accepting the failure modes — of full form-style validation on every single write.
What we're doing: Update only one field on an existing instance, avoiding a full-row UPDATE and avoiding overwriting other columns changed concurrently by another process.
- 3
- update_fields=["status"] tells Django to UPDATE only the status column — every other field on this in-memory instance (even if it happens to differ from what's currently in the database, e.g. changed by another process) is left untouched.
Why this works: A plain order.save() would UPDATE every column on the model, including any that another concurrent request may have changed since this instance was loaded — update_fields narrows the write to exactly the column this function actually intends to change, avoiding accidentally clobbering an unrelated concurrent update.
Assuming save() validates the data being written
Wrong
Better
What you see: Invalid data (a status outside choices=, a value violating a custom clean() rule) is saved successfully with no exception raised anywhere — the bug only surfaces later, wherever that value is read and doesn't match what the code expects.
Why: A ModelForm calls full_clean() (via its own validation) before its save() — but calling Model.save() directly, from a view, a script, or a shell, skips validation entirely unless full_clean() is called explicitly first. save() and full_clean() are two genuinely separate steps in Django, not one combined operation.
- 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
save() vs delete()
Together
Remember: 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.
See also: clean and full clean · instance methods and domain logic · constraints and indexes

