Defining models

Django · Essentials · 14 min

Models are the single source of truth for your data; the ORM, admin, forms and migrations all derive from them.

A model is a class subclassing models.Model; each class attribute that is a field becomes a column:

  • text: CharField(max_length=200), TextField(), SlugField(), EmailField(), URLField()
  • numbers: IntegerField, PositiveIntegerField, DecimalField(max_digits=8, decimal_places=2) for money, FloatField
  • others: BooleanField, DateField, DateTimeField, UUIDField, JSONField, FileField, ImageField

Every model gets an automatic primary key id, a 64-bit BigAutoField by default in Django 6.0.

Common field options:

  • null=True: the database column allows NULL
  • blank=True: forms and validation allow an empty value
  • default=...: Python-side default; db_default=... sets it in the database
  • unique=True, db_index=True, verbose_name, help_text
  • choices=: limit values, usually with a TextChoices or IntegerChoices enum. Django adds get_<field>_display() for the label.

null and blank are different: one is about the database, the other about validation. For text fields, prefer blank=True with an empty string over null=True, so there is only one "empty" value.

DateTimeField(auto_now_add=True) sets the creation time once; auto_now=True updates on every save.

Always define __str__, since it is used in the admin, the shell and error messages. Model options go in an inner class Meta, such as ordering, verbose_name_plural, indexes and constraints.

Example

# blog/models.py
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

    def __str__(self):
        return self.name

class Post(models.Model):
    class Status(models.TextChoices):
        DRAFT = "draft", "Draft"
        PUBLISHED = "pub", "Published"

    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    body = models.TextField(blank=True)
    status = models.CharField(max_length=5, choices=Status, default=Status.DRAFT)
    views = models.PositiveIntegerField(default=0)
    created = models.DateTimeField(auto_now_add=True)
    class Meta:
        ordering = ["-created"]
    def __str__(self):
        return self.title      # post.get_status_display() -> "Published"

Remember

  • Subclass models.Model; field attributes become columns
  • null is about the database, blank about validation
  • Use TextChoices/IntegerChoices for fixed sets of values
  • Always define __str__

Watch out for

  • Using null=True on CharField/TextField, giving two kinds of empty: NULL and "".

Check yourself

  1. A form should allow leaving a CharField empty. What do you set?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.djangoproject.com/en/6.0/topics/db/models/