现在位置: 首页 > Django 教程 > 正文

模型与数据库

本章你将学会用 Django ORM 定义数据模型,创建数据库表,并插入测试数据。


为什么需要模型?

上一章我们硬编码了页面文字。真正的博客需要存储多篇文章,且内容随时会变。

模型(Model) 是 Django 的数据库层:用 Python 类定义数据结构,Django 自动生成对应的数据库表。

你不需要写一行 SQL——这就是 ORM(对象关系映射) 的核心价值。


定义 Post 模型

打开 blog/models.py,定义文章模型。

实例

# 文件路径: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()VARCHARURL 友好的标识符
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,可以在里面操作数据库。

实例

# 在 Django 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_postQuerySet(所有文章)
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 DESCQuerySet
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 查询插入数据。

至此,文章和分类的结构已在数据库中建立。