Models and the ORM: defining your data
A Django model is a Python class that describes a database table — one class attribute per column, with the type of each attribute telling Django (and the eventual database) what kind of data belongs there. This part defines Post, the model the rest of the series builds around.
The Post model
# blog/models.py
from django.db import models
from django.conf import settings
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.titleEvery model inherits from models.Model — that's what gives it a database table, a manager (Post.objects), and everything else the ORM provides. CharField needs max_length because it maps to a fixed-width SQL column; TextField doesn't, since it's meant for unbounded content like a post body.
Field types worth understanding now
SlugField— a URL-safe version of a title ("My First Post"→"my-first-post"), used for readable URLs in part 10.unique=Truestops two posts from ever generating the same URL.ForeignKey— a link to another model.settings.AUTH_USER_MODELpoints at whichever user model the project uses (almost always Django's built-inUser) rather than importing it directly, which keeps this model working even if a project later swaps in a custom user model.on_delete=models.CASCADEmeans deleting a user deletes their posts too — the other common option,models.SET_NULL, is covered whenCommentneeds different behavior in part 11.auto_now_addvsauto_now—auto_now_addsets the timestamp once, on creation, and never touches it again;auto_nowupdates it on every save. Mixing these up is how a post's original publish date silently becomes "whenever it was last edited."
Meta and __str__
class Meta: ordering = ["-created_at"] sets the default order every query returns posts in — newest first, without needing .order_by() on every call site. __str__ isn't optional in any meaningful sense: without it, every Post shows up as Post object (1) in the admin (part 7) and the shell, instead of its actual title.
Defining a model and expecting a database table to exist immediately. It doesn't — a model is a Python description of a table, and the table itself only gets created once makemigrations generates a migration and migrate applies it, which is exactly what part 6 covers next.