Skip to content

模型层 ORM

ORM 是 Django 非常核心的一部分。它的价值在于:让你可以用 Python 的方式操作数据库,而不是一上来就把大量 SQL 硬写在项目里。

这并不代表你以后可以完全不学 SQL,而是说 Django 给了你一种更自然、更工程化的方式来处理数据。

本节目标

  • 理解模型和数据表之间的关系
  • 学会定义 Django 模型
  • 理解字段类型
  • 学会配置数据库连接
  • 学会执行迁移
  • 学会使用 ORM 做增删改查
  • 理解模型关系的基础概念

什么是模型

你可以先把模型理解成:

  • Python 里的一个类
  • 同时又对应数据库里的一张表

例如:

python
from django.db import models


class Student(models.Model):
    name = models.CharField(max_length=50)
    age = models.IntegerField()
    city = models.CharField(max_length=50)

这段代码的大致意思是:

  • 你定义了一个 Student
  • Django 会把它映射成数据库中的一张数据表
  • 表中有 nameagecity 这些字段

所以 Django 模型不是普通类,它带着“映射到数据库”的意义。

为什么 ORM 有价值

如果完全手写 SQL,你当然也能操作数据库,但项目一复杂后会遇到这些问题:

  • SQL 很多,代码不够清晰
  • 查询结果和 Python 对象之间切换麻烦
  • 模型关系维护成本高
  • 重复操作很多

ORM 的优势是:

  • 用 Python 代码描述数据结构
  • 用 Python 代码完成很多常见查询
  • 让模型关系表达更自然

定义第一个模型

打开 models.py

python
from django.db import models


class Student(models.Model):
    name = models.CharField(max_length=50)
    age = models.IntegerField()
    city = models.CharField(max_length=50)

字段分别是什么意思

  • CharField(max_length=50):字符串字段,最大长度 50
  • IntegerField():整数类型字段

这个模型表示:一条学生数据至少包含姓名、年龄、城市。

常见字段类型

字符串字段

python
models.CharField(max_length=100)

适合:

  • 姓名
  • 标题
  • 城市

长文本字段

python
models.TextField()

适合:

  • 文章正文
  • 课程介绍
  • 评论内容

整数字段

python
models.IntegerField()

适合:

  • 年龄
  • 数量
  • 排序值

布尔字段

python
models.BooleanField(default=False)

适合:

  • 是否发布
  • 是否热门
  • 是否启用

日期时间字段

python
models.DateTimeField(auto_now_add=True)

适合:

  • 创建时间
  • 发布时间

一个更完整的模型示例

python
from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    is_public = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

这个模型已经很接近真实项目中的文章表结构了。

配置数据库连接

如果你只是做最基础练习,Django 默认的 SQLite 就可以用。

但如果你要连接 MySQL,可以在 settings.py 中配置:

python
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "study_db",
        "USER": "root",
        "PASSWORD": "123456",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    }
}

这里分别表示:

  • 使用 MySQL 引擎
  • 数据库名
  • 用户名
  • 密码
  • 主机地址
  • 端口

如果是 SQLite,配置会简单得多,Django 默认就已经帮你准备好了。

模型写完后为什么还要迁移

很多初学者会误以为:我在 models.py 里写完模型,数据库里就自动有表了。

不是这样。

模型代码只是“描述结构”,真正同步到数据库,还需要执行迁移。

makemigrationsmigrate

第一步:生成迁移文件

bash
python manage.py makemigrations

它的作用是:

  • 发现模型变化
  • 生成数据库结构变更说明

第二步:执行迁移

bash
python manage.py migrate

它的作用是:

  • 把迁移真正应用到数据库

可以简单理解成:

  • makemigrations:生成变更计划
  • migrate:执行变更计划

新增数据

方法一:直接创建

python
Student.objects.create(name="小明", age=18, city="上海")

这条语句执行后,数据库里就会新增一条学生记录。

方法二:先创建对象再保存

python
stu = Student(name="小红", age=19, city="杭州")
stu.save()

这两种方式都常见。

查询数据

查询全部

python
students = Student.objects.all()

for item in students:
    print(item.name)

输出结果示例:

text
小明
小红

条件查询

python
students = Student.objects.filter(age__gte=18)

这里的意思是:

  • 查询年龄大于等于 18 的学生

查询单条

python
stu = Student.objects.get(id=1)
print(stu.name)

如果数据库中 id=1 对应的是“小明”,输出可能是:

text
小明

修改数据

python
stu = Student.objects.get(id=1)
stu.city = "深圳"
stu.save()

这表示:

  1. 先查出一条记录
  2. 修改字段值
  3. 再保存回数据库

删除数据

python
stu = Student.objects.get(id=1)
stu.delete()

执行后,这条记录会从数据库中删除。

一个完整的增删改查流程示例

新增

python
Student.objects.create(name="小刚", age=20, city="北京")

查询

python
students = Student.objects.all()
for item in students:
    print(item.name, item.city)

输出示例:

text
小刚 北京

修改

python
stu = Student.objects.get(name="小刚")
stu.city = "广州"
stu.save()

删除

python
stu = Student.objects.get(name="小刚")
stu.delete()

这就是最基础的 CRUD:

  • Create
  • Read
  • Update
  • Delete

模型关系

现实业务里,数据表之间往往不是孤立的。

例如:

  • 一个分类下有多篇文章
  • 一个作者写多篇文章
  • 一篇文章可能对应多个标签

这时就需要关系字段。

一对多:ForeignKey

例如:

  • 一个分类
  • 多篇文章属于这个分类
python
class Category(models.Model):
    name = models.CharField(max_length=50)


class Article(models.Model):
    title = models.CharField(max_length=100)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

这表示:

  • 每篇文章对应一个分类
  • 一个分类可以对应多篇文章

多对多:ManyToManyField

例如:

  • 一篇文章可以有多个标签
  • 一个标签也可以对应多篇文章
python
class Tag(models.Model):
    name = models.CharField(max_length=30)


class Article(models.Model):
    title = models.CharField(max_length=100)
    tags = models.ManyToManyField(Tag)

一对一:OneToOneField

例如:

  • 一个用户对应一份详细资料
python
class UserProfile(models.Model):
    user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
    phone = models.CharField(max_length=20)

零基础阶段你先知道这些关系分别在表达什么即可,不必一上来就追求全会。

在 Django shell 中测试 ORM

调试 ORM 最方便的方式之一是:

bash
python manage.py shell

进入 shell 后可以直接写:

python
from users.models import Student
Student.objects.create(name="小明", age=18, city="上海")
Student.objects.all()

这非常适合你练习模型操作。

常见错误

1. 改了模型,但没迁移

你改完 models.py 后,如果忘了:

bash
python manage.py makemigrations
python manage.py migrate

数据库结构就不会同步更新。

2. get() 查不到或查出多条

get() 适合查唯一结果,如果没有唯一性保障,可能会报错。

3. 字段类型选错

例如本来是长文本,却用了很短的 CharField;本来是布尔值,却用了字符串字段。

4. 忘记给 app 注册

如果 app 没有加入 INSTALLED_APPS,模型相关操作可能根本不会被 Django 正常识别。

练习题

练习 1

定义一个 Course 模型,包含:

  • 课程名
  • 价格
  • 简介

练习 2

执行迁移,让数据库中真正生成对应数据表。

练习 3

在 Django shell 中新增 3 条课程数据。

练习 4

查询所有课程,并打印课程名。

练习 5

再定义一个 Teacher 模型,并尝试让课程和老师建立一对多关系。

本节小结

ORM 的核心意义,是让你用 Python 的方式描述和操作数据库。

你这一节最重要的收获应该是:

  • 模型就是数据库表的 Python 表达
  • 字段类型决定数据如何存储
  • 模型变更后必须迁移
  • ORM 可以完成基础增删改查
  • 关系字段用于表达表与表之间的联系

只要这一层打牢,后面你做 Django 网站开发时,数据这一块就有了真正的抓手。

Built with VitePress.