模型与数据库
本章你将学会用 Django ORM 定义数据模型,创建数据库表,并插入测试数据。
为什么需要模型?
上一章我们硬编码了页面文字。真正的博客需要存储多篇文章,且内容随时会变。
模型(Model) 是 Django 的数据库层:用 Python 类定义数据结构,Django 自动生成对应的数据库表。
你不需要写一行 SQL——这就是 ORM(对象关系映射) 的核心价值。
定义 Post 模型
打开 blog/models.py,定义文章模型。
实例
from django.db import models
from django.utils import timezone
class Category(models.Model):
"""文章分类"""
name = models.CharField('分类名', max_length=50, unique=True)
# slug 用于 URL 中的英文标识(如 /category/django/)
slug = models.SlugField('URL 标识', max_length=50, unique=True)
class Meta:
verbose_name = '分类'
verbose_name_plural = '分类'
def __str__(self):
return self.name
class Post(models.Model):
"""博客文章"""
# 标题:CharField 用于短文本,max_length 必填
title = models.CharField('标题', max_length=200)
# slug:文章在 URL 中的英文标识
slug = models.SlugField('URL 标识', max_length=200, unique=True)
# 摘要:TextField 用于长文本,blank=True 表示可选
summary = models.TextField('摘要', blank=True)
# 正文:TextField 不限长度
content = models.TextField('正文')
# 分类:ForeignKey 一对多关系,一篇文章属于一个分类
# on_delete=models.CASCADE 表示删除分类时,其下所有文章也一并删除
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
verbose_name='分类',
related_name='posts' # 反向查询:category.posts.all()
)
# auto_now_add:创建时自动填入当前时间
created_at = models.DateTimeField('创建时间', auto_now_add=True)
# auto_now:每次保存时自动更新为当前时间
updated_at = models.DateTimeField('更新时间', auto_now=True)
class Meta:
verbose_name = '文章'
verbose_name_plural = '文章'
# 默认按创建时间倒序排列
ordering = ['-created_at']
def __str__(self):
# 在 Admin 后台和 Shell 中显示对象时,显示标题
return self.title
常用字段类型速查
| 字段类型 | 对应数据库类型 | 使用场景 |
|---|---|---|
| CharField(max_length=N) | VARCHAR(N) | 标题、标签、名称等短文本 |
| TextField() | TEXT | 文章正文、简介、评论等内容 |
| IntegerField() | INTEGER | 计数、年龄等整数 |
| DateTimeField() | DATETIME | 发布时间、更新时间 |
| ForeignKey() | 外键约束 | 一对多关系(文章→分类) |
| ManyToManyField() | 中间表 | 多对多关系(文章←→标签) |
| SlugField() | VARCHAR | URL 友好的标识符 |
| ImageField() | VARCHAR(路径) | 封面图、头像(需 Pillow 库) |
__str__方法决定了对象如何以字符串形式显示。在 Admin 后台的下拉选择框和 Shell 输出中,都会调用它来展示对象名称。不写这个方法,你会看到Post object (1)这样的无意义文字。
迁移:将模型同步到数据库
模型类写好后,需要用 迁移(Migration) 建立数据库表。
(venv) $ python manage.py makemigrations # 生成迁移文件(检测模型变化)
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Category
- Create model Post
(venv) $ python manage.py migrate # 执行迁移(创建数据库表)
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0001_initial... OK
两个命令的分工:
- makemigrations:扫描 models.py,生成迁移脚本(Python 文件)
- migrate:执行迁移脚本,在数据库中创建真实的表
每次修改 models.py 后,都要运行
makemigrations+migrate这两个命令。缺一不可:只 makemigrations 没 migrate,表不会创建;直接 migrate 不 makemigrations,Django 不知道你改了模型。
用 Django Shell 插入测试数据
在开始写页面之前,先用 Django Shell 往数据库里录入几条数据,验证模型是否正常工作。
(venv) $ python manage.py shell
这会打开一个交互式 Python Shell,可以在里面操作数据库。
实例
from blog.models import Category, Post
# 1. 创建分类
cat_django = Category.objects.create(name='Django', slug='django')
cat_python = Category.objects.create(name='Python', slug='python')
cat_css = Category.objects.create(name='CSS', slug='css')
# 2. 创建文章
Post.objects.create(
title='Django 入门完全指南',
slug='django-beginner-guide',
summary='从零开始学习 Django,涵盖模型、视图、模板等核心概念。',
content='<h2>为什么学 Django?</h2><p>Django 是 Python 最流行的 Web 框架之一...</p>',
category=cat_django
)
Post.objects.create(
title='Python 异步编程详解',
slug='python-async',
summary='一文搞懂 asyncio、协程、事件循环。',
content='<h2>什么是协程?</h2><p>协程是一种比线程更轻量的并发方案...</p>',
category=cat_python
)
Post.objects.create(
title='CSS Grid 布局实战',
slug='css-grid-layout',
summary='用 CSS Grid 轻松实现复杂的响应式布局。',
content='<h2>Grid 入门</h2><p>Grid 是二维布局系统...</p>',
category=cat_css
)
# 3. 验证查询
print(Post.objects.all()) # 输出所有文章
print(Post.objects.count()) # 文章总数
print(Post.objects.filter(category=cat_django)) # Django 分类下的文章
Django ORM 基础查询
ORM 让你用 Python 方法链操作数据库,无需写 SQL。
| 方法 | 等价 SQL | 返回值 |
|---|---|---|
Post.objects.all() | SELECT * FROM blog_post | QuerySet(所有文章) |
Post.objects.get(id=1) | SELECT ... WHERE id=1 | 单个对象(找不到会抛异常) |
Post.objects.filter(category__slug='django') | WHERE category.slug='django' | QuerySet |
Post.objects.order_by('-created_at') | ORDER BY created_at DESC | QuerySet |
Post.objects.exclude(status='draft') | WHERE status != 'draft' | QuerySet |
QuerySet 是 惰性求值 的:定义了查询不会立即执行,只有在真正需要数据时(如遍历、打印、转为 list)才发 SQL。所以你可以链式调用多个 filter 而不产生多次查询。
动手:为后续章节准备数据
在 Shell 中多录入几篇文章和分类,覆盖 Django、Python、CSS 三个分类,每个分类至少 2 篇文章。
可以编写一个管理命令或脚本批量插入,但现阶段用 Shell 逐条插入足够了。
本章小结
本章你掌握了 Django ORM 的核心流程:在 models.py 中定义 Python 类(模型)、makemigrations 生成迁移文件、migrate 同步到数据库、用 Shell 和 ORM 查询插入数据。
至此,文章和分类的结构已在数据库中建立。
