CodeMIRAI
0 XP

Models

3 min read 3 runnable examples Quiz included

A model is a Python class that describes a table in your database: each attribute is a column, and each object is a row.

A first model

In a project, models go in an app's models.py. Here, the setup lines at the top stand in for a project: they configure Django with an in-memory database, and create_model creates the table, the job migrations normally do.

class Book(models.Model):title = CharField(...)year = IntegerField()author = ForeignKey(...)makemigrationsthen migratetable app_bookidtitleyear1Dune19652Emma1815Book.objects.filter(year__lt=1900) becomes SQL for you
A model class describes a table; migrations create or change it; the ORM turns Python queries into SQL.
Python
import django
from django.conf import settings

settings.configure(
    INSTALLED_APPS=["django.contrib.contenttypes"],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
)
django.setup()

from django.db import connection, models


class Course(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    price = models.DecimalField(max_digits=8, decimal_places=2, default=0)
    published = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        app_label = "courses"       # in a project, the app's folder supplies this
        ordering = ["title"]

    def __str__(self):
        return self.title


with connection.schema_editor() as editor:
    editor.create_model(Course)

python = Course.objects.create(title="Python", price=499, published=True)
Course.objects.create(title="SQL", price=299)
print(python.id, python, python.price, python.published)
print(Course.objects.all())
  • Every model gets an automatic id primary key.
  • Course.objects.create(...) inserts a row and returns the object.
  • __str__ decides how an object is shown: in the admin, in the shell, and in printed querysets like the last line.
  • Meta.ordering sets the default order for queries.

Common field types

FieldStores
CharField(max_length=...)short text; max_length is required
TextField()long text
IntegerField(), PositiveIntegerField()whole numbers
DecimalField(max_digits, decimal_places)exact decimals, such as prices
FloatField()approximate decimals
BooleanField()True or False
DateField(), DateTimeField()dates and times
EmailField(), URLField(), SlugField()text with validation
ImageField(), FileField()uploaded files

Field options

OptionEffect
default=...the value when none is given
null=Truethe database column may hold NULL
blank=Trueforms may leave the field empty
unique=Trueno two rows may share the value
choices=...a fixed set of allowed values
auto_now_add=Trueset to the current time when the row is created
auto_now=Trueset to the current time on every save

null is about the database; blank is about validation in forms. For text fields, Django's convention is blank=True without null=True, so "empty" is always stored as "".

Choices

Python
import django
from django.conf import settings

settings.configure(
    INSTALLED_APPS=["django.contrib.contenttypes"],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
)
django.setup()

from django.db import connection, models


class Course(models.Model):
    class Level(models.TextChoices):
        BEGINNER = "beg", "Beginner"
        INTERMEDIATE = "int", "Intermediate"
        ADVANCED = "adv", "Advanced"

    title = models.CharField(max_length=100)
    level = models.CharField(max_length=3, choices=Level.choices, default=Level.BEGINNER)

    class Meta:
        app_label = "courses"


with connection.schema_editor() as editor:
    editor.create_model(Course)

c = Course.objects.create(title="React", level=Course.Level.INTERMEDIATE)
print(c.level, "|", c.get_level_display())
print(Course.objects.filter(level=Course.Level.INTERMEDIATE).count())

The database stores the short code, "int", while get_level_display() gives the readable label, "Intermediate". Forms and the admin automatically show a drop-down of the choices.

Relationships

Python
import django
from django.conf import settings

settings.configure(
    INSTALLED_APPS=["django.contrib.contenttypes"],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
)
django.setup()

from django.db import connection, models


class Course(models.Model):
    title = models.CharField(max_length=100)

    class Meta:
        app_label = "courses"

    def __str__(self):
        return self.title


class Lesson(models.Model):
    course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="lessons")
    title = models.CharField(max_length=100)
    minutes = models.PositiveIntegerField(default=10)

    class Meta:
        app_label = "courses"

    def __str__(self):
        return self.title


with connection.schema_editor() as editor:
    editor.create_model(Course)
    editor.create_model(Lesson)

python = Course.objects.create(title="Python")
Lesson.objects.create(course=python, title="Variables", minutes=8)
Lesson.objects.create(course=python, title="Loops", minutes=12)

first = Lesson.objects.get(title="Loops")
print(first.course)                       # follow the link forwards
print(python.lessons.all())               # and backwards, through related_name
print(python.lessons.count(), "lessons")
  • ForeignKey links many lessons to one course: a many-to-one relationship.
  • on_delete=models.CASCADE deletes a course's lessons when the course is deleted. PROTECT refuses to delete a course that still has lessons, and SET_NULL keeps them with an empty link.
  • related_name="lessons" names the reverse direction, so python.lessons.all() lists a course's lessons.

The other two relationships:

Python
class Student(models.Model):
    name = models.CharField(max_length=100)
    courses = models.ManyToManyField(Course, related_name="students")   # many-to-many


class Profile(models.Model):
    student = models.OneToOneField(Student, on_delete=models.CASCADE)   # one-to-one
    bio = models.TextField(blank=True)

A student takes many courses and a course has many students, so that's a many-to-many field; Django creates the linking table for you. A one-to-one field is a ForeignKey that allows only one row on each side, which suits extra details about another model.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.