Python Django Tutorial: Full-Featured Web App Part 5 - Database and Migrations
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Define a `Post` model with `title`, `content`, `date_posted`, and an `author` foreign key to `User` to replace dummy data with real database-backed posts.
Briefing
Django’s ORM turns database design into Python models, letting developers create real blog posts with zero hand-written SQL—then query, format, and manage that data through both the app and the admin site. The core move is defining a `Post` model with fields for `title`, `content`, `date_posted`, and an `author` relationship to Django’s built-in `User`, then using migrations to materialize those models as database tables.
The `Post` model is built in `models.py` by inheriting from `models.Model`. The tutorial defines `title` as a `CharField` capped at 100 characters, `content` as a `TextField` for longer text, and `date_posted` as a `DateTimeField` whose default value comes from `timezone.now` (passed as a function, not called immediately). For authorship, it adds an `author` field using `models.ForeignKey` pointing to the `User` model, with `on_delete=models.CASCADE` so deleting a user automatically deletes their posts. This establishes a one-to-many structure: one user can write many posts, while each post has exactly one author.
Once the model exists, the database changes happen through Django migrations. Running `python manage.py makemigrations` generates a migration file (e.g., `0001_initial.py`) describing the new schema. The tutorial then demonstrates how to inspect the exact SQL Django will run using `python manage.py sqlmigrate blog 0001`, where the output includes a `CREATE TABLE` for `blog_post` and column definitions that match the model fields (including an auto-incrementing primary key). Finally, `python manage.py migrate` applies the migration to the actual database.
With the table created, the Django shell (`python manage.py shell`) becomes a live playground for ORM queries. It shows how to list users (`User.objects.all()`), filter them (`filter(username=...)`), and fetch single records (`first()`, `get(id=...)`). It then creates `Post` objects tied to a user, highlights the need to call `.save()` when creating objects directly, and verifies that `date_posted` auto-populates from the model default. Adding a `__str__` method returning `self.title` makes query results readable in the shell.
The tutorial also demonstrates reverse relationships: from a user instance, `user.post_set.all()` retrieves all posts authored by that user. It even creates a post via `user.post_set.create(...)`, which automatically assigns the author and saves to the database without an explicit `.save()`.
To replace earlier dummy data, `blog/views.py` is updated to pull real posts from `Post.objects.all()` and pass them into templates. Because database timestamps look awkward in raw form, the `home.html` template formats `date_posted` using Django’s `date` filter with format codes (full month, day, and year). The final step registers the `Post` model in `blog/admin.py` so posts appear in the admin panel, where titles, content, and authors can be edited through a GUI.
Overall, the workflow ties together schema definition (models), safe database evolution (migrations), data access (ORM queries), presentation (template formatting), and management (admin registration) into one coherent system for a full-featured blog app.
Cornell Notes
The tutorial builds a real blog database by defining a `Post` model in Django and letting migrations create the corresponding SQL table. The model includes `title` (`CharField` with `max_length=100`), `content` (`TextField`), `date_posted` (`DateTimeField` defaulting to `timezone.now`), and an `author` foreign key to Django’s built-in `User` with `on_delete=models.CASCADE`. After running `makemigrations`, inspecting generated SQL with `sqlmigrate`, and applying changes with `migrate`, the ORM is used to create and query posts in the Django shell. The app then replaces dummy post data in `views.py` with `Post.objects.all()`, formats timestamps in the template using the `date` filter, and registers `Post` in `admin.py` so posts can be managed through the admin interface.
Why does the `Post` model use `timezone.now` as the default for `date_posted`, and why is it passed without parentheses?
What does `on_delete=models.CASCADE` do for the `author` foreign key?
How can developers see the exact SQL Django will generate before applying migrations?
What’s the difference between creating a `Post` directly and creating one via `user.post_set.create(...)`?
How does the tutorial format `date_posted` so it looks like a normal date in templates?
How does the admin interface gain the ability to edit posts?
Review Questions
- What fields and relationship does the `Post` model define, and how does `on_delete=models.CASCADE` affect data integrity?
- Walk through the migration workflow used here: `makemigrations`, `sqlmigrate`, and `migrate`. What does each step accomplish?
- In the Django shell, how do you retrieve all posts written by a specific user, and what reverse relationship name is used?
Key Points
- 1
Define a `Post` model with `title`, `content`, `date_posted`, and an `author` foreign key to `User` to replace dummy data with real database-backed posts.
- 2
Use `default=timezone.now` (without parentheses) for `date_posted` so each post gets a creation timestamp at the moment it’s created.
- 3
Run `python manage.py makemigrations` to generate schema changes, inspect them with `python manage.py sqlmigrate blog 0001`, and apply them with `python manage.py migrate`.
- 4
Use the Django ORM in `python manage.py shell` to create and query objects; remember to call `.save()` when creating instances directly.
- 5
Add a `__str__` method (e.g., returning `self.title`) so posts display clearly in query results and admin listings.
- 6
Replace dummy post dictionaries in `views.py` with `Post.objects.all()` and format `date_posted` in templates using the `date` filter.
- 7
Register the `Post` model in `blog/admin.py` so posts become editable through the admin panel, including changing the author via a dropdown.