skip to content

In Django's ORM, what does Model.objects.create() do, and how does it differ from building an instance and calling save()?

level: juniorimportance: should knowfreq 52%

answer

  1. one call, one statement
  2. returns the saved instance, not a tuple
  3. force_insert under the hood
  4. save() with a hand-set pk may UPDATE

basics

~20 s

Model.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 lines
python
from 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 key

go deeper

for a junior

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.

for a middle

Explain force_insert: create() always inserts, while save() with a hand-set primary key tries an UPDATE first and inserts only when nothing matched.

for a senior

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.

for a principal

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