models.py and Migrations
The cookbook needs somewhere to keep its recipes. You could write CREATE TABLE by hand, then keep the SQL, the Python and every teammate's database in sync forever. Django lets you describe the table once, in Python, and generates the database changes for you, in recorded steps anyone can replay.
The rule
Describe in models.py;
makemigrationswrites the plan;migratebuilds it.
A model is a class that becomes a table. Each field becomes a column:
# recipes/models.py
from django.db import models
class Recipe(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
minutes = models.PositiveIntegerField()
instructions = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titleWhat you get:
- A table named
recipes_recipe(app name, underscore, model name in lower case). - An automatic
idprimary key; you did not write it. - Rules in the fields:
CharFieldmust havemax_length;unique=Trueforbids two recipes with the same slug;blank=Truelets forms leave instructions empty;auto_now_add=Truestamps the creation time. __str__gives each recipe a readable name in the shell and the admin.
Writing the class changes nothing in the database yet. Two commands do that:
python manage.py makemigrations # writes recipes/migrations/0001_initial.py
python manage.py migrate # applies it: the table now existsA migration is a small Python file listing operations such as "create model Recipe" or "add field servings". Migrations are numbered and chained, and Django records which ones each database has applied, so migrate only runs the new ones. Curious what SQL it will run? python manage.py sqlmigrate recipes 0001 prints it.
Migration files are part of your code: commit them. Teammates and servers run migrate and get exactly the same tables.
The shortcut
Every model change is the same three beats: edit, make, migrate. If the database seems out of step with your models, ask which beat was skipped.
Edit
Add
servings = models.PositiveIntegerField(default=2). Existing rows need a value, hence the default.
The trap is running only makemigrations and wondering why the page crashes with "no such column". The plan is written; it has not been built.
Drills
Answer fast — trust the rule.
What does python manage.py makemigrations change in the database?
What table does the Recipe model in the recipes app create by default?
Which field definition is an error?
Should migration files be committed to Git?
You added a field and ran makemigrations, but the page says "no such column". What is missing?
Remember
- Describe in
models.py;makemigrationswrites the plan;migratebuilds it. - Edit, make, migrate, then commit the model and the migration together.
- Trap: a written but unapplied migration means "no such column".
