Filter concepts by levelShowing all levels.

Django · Django Models

Django Models

Primary keys, field-level options, and the two Meta option groups

  • default=uuid.uuid4, not uuid.uuid4()pass the callable, not a call
  • db_index/unique are database-leveldb_column renames only the column
  • Meta.ordering skips GROUP BY queriesannotate()/aggregate() need explicit order_by()
  • UniqueConstraint can be conditionalcondition=Q(...) makes it a partial constraint

1.Primary keys and field-level options

Django adds an auto-incrementing id (AutoField) primary key unless a field is explicitly marked primary_key=True — a UUIDField with default=uuid.uuid4 is a common non-sequential alternative. db_index=True and unique=True add a database-level index/constraint; db_column renames just the underlying column, independent of the Python attribute name.

Key features

  • Every model gets `id = models.AutoField(primary_key=True)` automatically, unless another field sets primary_key=True
  • A UUIDField primary key needs default=uuid.uuid4 (a callable, not uuid.uuid4() — see the mistake below) and usually editable=False
  • db_index=True adds a plain database index for faster lookups on that column
  • unique=True adds a database-level UNIQUE constraint, enforced by the database itself, not just Django
  • db_column renames the underlying database column without changing the Python attribute name used everywhere else

Field-level lookup and naming options

Field-level lookup and naming options
OptionEffect
primary_key=Truethis field IS the primary key — disables the automatic id
default=value (or callable)value used when none is provided at creation
editable=Falseexcluded from ModelForm/admin editing — still settable in code
db_index=Trueadds a plain index on this column
unique=Trueadds a database-level UNIQUE constraint
db_column="name"the real column name, if different from the Python attribute
Sequential id vs UUID primary key

AutoField (default id)

  • Sequential, predictable
  • Row 42 was likely created before row 100
  • Compact, sortable by creation order

UUIDField (default=uuid.uuid4)

  • Non-sequential — not guessable
  • Safe for public-facing URLs
  • Needs the callable, not a call: uuid.uuid4
  • AutoField (default id)
    • Sequential, predictable
    • Row 42 was likely created before row 100
    • Compact, sortable by creation order
  • UUIDField (default=uuid.uuid4)
    • Non-sequential — not guessable
    • Safe for public-facing URLs
    • Needs the callable, not a call: uuid.uuid4

Command

python
import uuid

class Order(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

default=uuid.uuid4 (the callable, not a call) for a UUID primary key; db_index/unique are enforced by the database itself; db_column renames only the underlying column, not the Python attribute.

2.Model Meta: db_table, verbose_name, ordering

class Meta inside a model configures the model itself rather than any one field — db_table renames the table, verbose_name/verbose_name_plural set the human-readable names Django uses (mainly in the admin), and ordering sets the default sort applied whenever no explicit .order_by() is given.

Key features

  • class Meta: lives inside the model class body, alongside the fields, not as a separate top-level class
  • db_table overrides the default table name (<app_label>_<modelname>, lowercased)
  • verbose_name/verbose_name_plural override the auto-derived (CamelCase → "camel case" + "s") admin display names
  • ordering = ["-pub_date", "author"] sorts descending by pub_date, then ascending by author, on EVERY unordered query
  • An explicit .order_by() call on a specific QuerySet always overrides Meta.ordering for that one query

Common Meta options

Common Meta options
OptionAffects
db_tablethe real database table name
verbose_name / verbose_name_pluralhuman-readable singular/plural, mainly in the admin
orderingdefault sort order for every unordered query on this model
What each Meta option controls

class Article(models.Model): title = models.CharField(max_length=200) published_at = models.DateTimeField() class Meta: db_table = "cms_article" verbose_name_plural = "Articles" ordering = ["-published_at"]

db_table = "cms_article"

db_table — overrides the default table name

verbose_name_plural = "Articles"

verbose_name_plural — the admin display name

ordering = ["-published_at"]

ordering — default sort for every unordered query — overridden by an explicit .order_by()

  • Whole: class Article(models.Model): title = models.CharField(max_length=200) published_at = models.DateTimeField() class Meta: db_table = "cms_article" verbose_name_plural = "Articles" ordering = ["-published_at"]
  • db_table = "cms_article" — db_table: overrides the default table name
  • verbose_name_plural = "Articles" — verbose_name_plural: the admin display name
  • ordering = ["-published_at"] — ordering: default sort for every unordered query — overridden by an explicit .order_by()

Command

python
class Article(models.Model):
    title = models.CharField(max_length=200)

    class Meta:
        ordering = ["-created_at"]

Meta.ordering sets the default sort for every unordered query on the model — an explicit .order_by() always overrides it, and it does NOT apply inside annotate()/aggregate() GROUP BY queries.

3.Meta.constraints and Meta.indexes

Meta.constraints (a list of UniqueConstraint/CheckConstraint) enforces data rules at the database level, spanning one or more fields — the modern replacement for the older unique_together. Meta.indexes (a list of models.Index) adds database indexes for query performance, independent of any constraint.

Key features

  • UniqueConstraint(fields=[...], name="...") enforces uniqueness across one or more fields together — the modern form of the deprecated unique_together
  • UniqueConstraint can be conditional: condition=Q(...) makes it a PARTIAL unique constraint, enforced only for matching rows
  • CheckConstraint(condition=Q(...), name="...") enforces an arbitrary row-level condition, like age__gte=18
  • models.Index(fields=[...], name="...") adds a plain index — a query-speed tool, unrelated to any constraint
  • Every constraint and index needs a unique name within the app — required, not optional, since name= identifies it in the migration

Constraint types vs. an index

Constraint types vs. an index
ToolEnforcesSpeeds up queries?
UniqueConstraintno two rows share these field(s) — optionally, only when condition matchesyes, as a side effect
CheckConstrainta row-level condition (age >= 18)no
models.Indexnothing — no rule at allyes, that's its only job
A constraint enforces a rule; an index only speeds up reads

UniqueConstraint / CheckConstraint

the database refuses to break this rule

models.Index

purely a performance structure — no rule attached

  1. UniqueConstraint / CheckConstraint — the database refuses to break this rule
  2. models.Index — purely a performance structure — no rule attached

Command

python
class Meta:
    constraints = [
        models.CheckConstraint(condition=models.Q(age__gte=18), name="age_gte_18"),
    ]
    indexes = [
        models.Index(fields=["last_name", "first_name"], name="name_idx"),
    ]

UniqueConstraint/CheckConstraint enforce rules at the database level (UniqueConstraint can be conditional via condition=Q(...)); models.Index is purely for query speed, with no rule attached — both need makemigrations/migrate to take effect.

Remember

  • default=uuid.uuid4 (the callable, not a call) for a UUID primary key.
  • db_index/unique are enforced by the database itself; db_column renames only the underlying column.
  • Meta.ordering sets the default sort for unordered queries — it does NOT apply inside annotate()/aggregate() GROUP BY.
  • UniqueConstraint/CheckConstraint enforce rules at the database level; models.Index is purely for query speed.

Pro tip

  • A conditional UniqueConstraint (condition=Q(...)) enforces uniqueness only for matching rows — e.g. one ACTIVE subscription per customer.
  • Every constraint/index needs a unique name — required, since it identifies the object in its migration.

Next up

  • Django Field Types
  • null vs blank
  • Relationships

Sources

  • Model field reference — docs.djangoproject.com/en/5.2/ref/models/fields/
  • Model Meta options — docs.djangoproject.com/en/5.2/ref/models/options/
  • Every claim checked against Django 5.2 LTS docs · checked 2026-08-21

Spotted a mistake on this page? Tell us.