In Django's ORM, what does Model.objects.create() do, and how does it differ from building an instance and calling save()?
answer
- one call, one statement
- returns the saved instance, not a tuple
- force_insert under the hood
- save() with a hand-set pk may UPDATE
basics
~20 sModel.objects.create(**kwargs) builds the instance and saves it with force_insert=True in one call, returning the saved object. It always issues an INSERT, while save() on an instance with a hand-set primary key may issue an UPDATE instead.
solid answer
~40 s`Workshop.objects.create(title=...)` is shorthand for `Workshop(title=...)` followed by `save(force_insert=True)`, and it returns the saved instance with its primary key filled in. Both paths go through the model's `save()`, so an overridden `save()` and the `pre_save`/`post_save` signals run either way, and neither calls `full_clean()`. The real difference is insert versus update: `create()` always emits an `INSERT`, so a duplicate hand-set primary key or a unique-constraint clash raises `IntegrityError`. A plain `save()` on an instance whose primary key you set yourself (on a pk field with no default) first tries an `UPDATE` by that key and inserts only if no row matched, which can silently overwrite an existing row. Build and `save()` when you need to adjust the object before it is written; use `create()` when you have all the values.
code
python · 20 linesfrom django.db import IntegrityError, models
class Workshop(models.Model):
title = models.CharField(max_length=200)
capacity = models.PositiveIntegerField()
# One call: INSERT, returns the saved instance with pk set.
intro = Workshop.objects.create(title="Intro", capacity=30)
# Hand-set pk + save(): UPDATE first, INSERT only if 0 rows matched.
clash = Workshop(pk=intro.pk, title="Overwritten", capacity=5)
clash.save() # silently overwrites the "Intro" row
# Same values through create(): always INSERT.
try:
Workshop.objects.create(pk=intro.pk, title="Dup", capacity=5)
except IntegrityError:
pass # duplicate primary keygo deeper
Recall that create() builds and saves in one call and returns the saved instance, and that it goes through save(), so signals and overridden save() run.
Explain force_insert: create() always inserts, while save() with a hand-set primary key tries an UPDATE first and inserts only when nothing matched.
Show where the difference bites in production: imports that set primary keys and call save() overwrite rows silently, while create() surfaces IntegrityError you must handle.
Frame the choice as a team convention: when to allow upsert-by-primary-key semantics at all, and where validation must be called explicitly because save() never runs it.
## What `create()` is In Django, every model gets a default **manager**, `objects`, and the manager exposes the **QuerySet** API. `create()` is the QuerySet method that writes one new row. In the Django 6.1 source it is only a few lines long: 1. It builds the model instance: `obj = self.model(**kwargs)`. 2. It saves it with `obj.save(force_insert=True, using=self.db)`. 3. It returns `obj`. So these two snippets are equivalent, as the reference documentation itself states: ```python w = Workshop.objects.create(title="Intro to Django", capacity=30) w = Workshop(title="Intro to Django", capacity=30) w.save(force_insert=True) ``` The return value is the **model instance**, already saved, with its primary key set from the database. It is not a tuple; the `(object, created)` tuple belongs to `get_or_create()` and `update_or_create()`. ## What both paths share Because `create()` delegates to `save()`, everything that hangs off `save()` runs in both cases: - an **overridden `save()`** on the model runs; - the **`pre_save` and `post_save` signals** are sent, with `created=True` on `post_save`; - field-level `pre_save()` hooks run, so `auto_now_add` and `auto_now` timestamps are filled in; - **no validation** runs: neither `create()` nor `save()` calls `full_clean()`, so a too-long string or a bad choice value reaches the database, which may or may not reject it. A keyword that is not a field fails before any SQL: the model constructor raises `TypeError` ("Workshop() got unexpected keyword arguments: ..."). ## Where they differ: INSERT versus UPDATE-then-INSERT The difference lives in how `save()` decides which statement to emit. Without `force_insert`, `Model.save()` follows roughly this logic: - if the primary key is **not set**, it inserts; - if the instance is new (`_state.adding` is true) and the primary key field **has a default** (for example a `UUIDField(default=uuid.uuid4)`), it inserts without trying an update; - otherwise, with a primary key set, it first runs an **`UPDATE ... WHERE pk = ...`** and, only if that matched no row, falls back to an **`INSERT`**. `create()` skips that decision by passing `force_insert=True`. The consequences are easiest to see side by side: | Situation | `Workshop(pk=7, ...).save()` | `Workshop.objects.create(pk=7, ...)` | |---|---|---| | No row with pk 7 exists | UPDATE matches 0 rows, then INSERT | INSERT | | A row with pk 7 exists | **UPDATE overwrites that row** | **`IntegrityError`** (duplicate key) | | pk not given (auto-increment field) | INSERT | INSERT | The overwrite case is the dangerous one: a data import that sets primary keys by hand and calls `save()` can replace existing rows without any error. `create()` turns the same mistake into a loud `IntegrityError`, which the documentation warns you to be ready for when you use manual primary keys. ## Errors you can meet - **`IntegrityError`** from `django.db` when the INSERT violates a primary-key, unique or foreign-key constraint. Inside a `transaction.atomic()` block the error also marks that block for rollback. - **`TypeError`** for an unknown keyword argument, raised by the constructor. - **`ValueError`** if you pass the name of a reverse one-to-one relation, which is not a field on this model. ## When to use which - Use **`create()`** when you have every value up front and want one call that returns a persisted object, typically in a view handling a POST or in a test fixture. - Build the instance and call **`save()`** when you need to compute or adjust something between construction and the write, for example setting a field that depends on the request user, or when you deliberately want update-or-insert semantics by primary key. - Use **`get_or_create()`** instead of either when the row may already exist and a duplicate must not be created. ## `create()` through a related manager `create()` also exists on **related managers**. `workshop.registration_set.create(email="[email protected]")` builds a `Registration`, fills its foreign key to `workshop` for you and saves it, again through `save()`. On a many-to-many manager, `workshop.speakers.create(name="Ada")` saves the new `Speaker` row first and then adds the link row in the intermediate table, so it costs more than one query. Everything else in this answer applies unchanged: the return value is the saved instance, validation is not run, and a unique clash raises `IntegrityError`. Since Django 5.2, `create()` (like `get_or_create()` and `bulk_create()`) has `alters_data=True`, so the template engine refuses to call it while rendering, a small guard against side effects triggered from a template.
- Does Django's create() validate field values the way a ModelForm does?No. `create()` calls `save()`, and `save()` never calls `full_clean()`. Constraints such as `max_length` or `choices` are checked only when you call `full_clean()` yourself or go through a `ModelForm`; otherwise the value goes to the database, which enforces only what its own schema enforces.
- In Django, what happens if you pass create() a keyword that is not a model field?The model constructor raises `TypeError` with a message like `Workshop() got unexpected keyword arguments: 'titel'`, before any SQL is sent. Lookups with double underscores are not accepted either, because `create()` takes field values, not filter expressions.
saying these in an interview costs you the question
- create() returns a tuple of the object and a created flag
- create() skips save(), so post_save signals do not fire
- create() runs full_clean() before inserting the row
- You must call save() after create() to persist the object
- save() on a new instance always issues an INSERT