第 66 课:Django 模型(Models)与 ORM
学习目标
完成本课学习后,你将能够:
- 理解 Django 模型(Model)的基本概念及其与数据库表的关系。
- 掌握使用 Django 模型类定义数据表结构(字段类型、选项)。
- 学会使用 Django ORM(对象关系映射)进行数据的创建(Create)、查询(Read)、更新(Update)和删除(Delete),即 CRUD 操作。
- 初步了解模型之间的关系(如一对多关系)的定义。
核心概念
在上一课中,我们创建了第一个 Django 项目和应用。现在,我们将学习如何使用模型来定义应用的数据结构。
1. 模型(Model)是什么? 想象一下,你在设计一个图书馆管理系统。你需要记录"图书"和"作者"的信息。在数据库里,你会创建"Books"表和"Authors"表。在 Django 中,模型(Model)就是用 Python 代码来定义这些数据库表结构的蓝图。每个模型类对应数据库中的一张表,类中的属性(字段)对应表中的列。
2. ORM 是什么? ORM 全称是 Object-Relational Mapping(对象关系映射)。你可以把它理解为一个"翻译官"。它让你可以用 Python 的代码(操作 Python 对象)来与数据库进行交互,而不需要直接编写 SQL 语句。当你创建、查询、修改或删除一个模型实例(数据库表中的一行记录)时,ORM 会自动将其翻译成对应的 SQL 语句并执行。
3. 主要步骤
- 在应用的
models.py文件中定义你的模型。 - 运行数据库迁移(Migrate)命令,让 Django 根据你的模型定义在数据库中创建(或修改)真实的表。
- 在视图、管理命令或其他代码中,使用 Django 提供的"管理器"(Manager,通常是
objects)通过 ORM 来操作数据。
代码示例
让我们为一个简单的博客系统创建两个模型:Author(作者)和 Article(文章)。一个作者可以有多篇文章。
首先,在你的应用(假设应用名为 blog)的 models.py 文件中编写如下代码:
# blog/models.py
from django.db import models
# 定义作者模型
class Author(models.Model):
# CharField: 字符串字段,max_length是必须参数
name = models.CharField(max_length=100)
email = models.EmailField(unique=True) # EmailField会进行邮箱格式验证,unique=True表示该字段值必须唯一
# 定义一个方法,让打印作者对象时显示名字,而不是默认的 "Author object (1)"
def __str__(self):
return self.name
# 定义文章模型
class Article(models.Model):
# 定义文章的标题(字符串)
title = models.CharField(max_length=200)
# 定义文章内容(长文本)
content = models.TextField()
# 定义发布日期和时间(自动设置为创建时的时间,之后不再更改)
pub_date = models.DateTimeField(auto_now_add=True)
# 定义作者字段,建立"多对一"关系
# ForeignKey表示多对一关系,'Author'指向Author模型
# on_delete=models.CASCADE 表示当关联的作者被删除时,该作者的所有文章也被删除
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# 同样,自定义打印输出
def __str__(self):
return self.title
代码解析:
models.Model: 所有 Django 模型都必须继承自django.db.models.Model。- 字段类型:
CharField(字符串)、EmailField(邮箱)、TextField(大文本)、DateTimeField(日期时间)、ForeignKey(外键,用于定义关系)。 - 字段选项:
max_length(最大长度)、unique(唯一)、auto_now_add(自动设置创建时间)。 __str__方法:这是一个 Python 魔术方法。当你打印一个模型实例(例如print(my_article))或将其显示在 Django 管理后台时,它决定了显示的内容,使数据更易读。
定义好模型后,我们需要创建迁移文件并执行迁移:
# 在项目根目录下执行
# 1. 创建迁移文件(根据models.py的变化生成一个记录)
python manage.py makemigrations
# 2. 执行迁移(在数据库中真正创建表)
python manage.py migrate
现在,让我们使用 ORM 来操作这些数据。这通常在 Django 视图、交互式 Shell 或管理命令中进行。这里我们使用 Django 交互式 Shell 来演示:
# 启动Django Shell
python manage.py shell
# 在Django Shell中演示ORM操作
from blog.models import Author, Article
from django.utils import timezone
# --- 创建数据(Create)---
# 1. 创建一个作者对象并保存到数据库
author_john = Author(name='John Doe', email='[email protected]')
author_john.save() # 调用save()方法将数据写入数据库
# 2. 创建文章,并关联到作者
article1 = Article(
title='Django入门指南',
content='本文介绍如何开始使用Django...',
author=author_john # 关联作者对象
)
article1.save()
# --- 查询数据(Read)---
# 1. 查询所有作者
all_authors = Author.objects.all()
print(all_authors) # <QuerySet [<Author: John Doe>]>
# 2. 根据条件查询单个作者
author = Author.objects.get(email='[email protected]')
print(author.name) # John Doe
# 3. 查询John Doe的所有文章
john_articles = article_set.all() # 通过反向关系查询
# 或者更明确地:john_articles = Article.objects.filter(author=author_john)
print(john_articles) # <QuerySet [<Article: Django入门指南>]>
# 4. 使用链式过滤
recent_articles = Article.objects.filter(pub_date__gte=timezone.now()).order_by('-pub_date')
# --- 更新数据(Update)---
# 更新作者的名字
author_john.name = 'John Smith'
author_john.save() # 必须再次调用save()来保存更改
# 或者,直接更新数据库中的多个对象
Author.objects.filter(name='John Smith').update(name='John Doe')
# --- 删除数据(Delete)---
# 删除特定的文章
article1.delete()
# 删除作者(注意:因为设置了on_delete=CASCADE,这也会删除该作者关联的所有文章!)
author_john.delete()
实践练习
练习一:基础模型定义
在一个新的 Django 应用 library 中,定义一个 Book 模型。
- 要求字段:
title(书名,字符串,最大200字符)、author(作者名,字符串,最大100字符)、isbn(国际标准书号,字符串,最大13字符,必须唯一)、published_date(出版日期)。 - 为
Book类添加__str__方法,返回书名。
练习二:ORM 基础操作
基于练习一的 Book 模型,在 Django Shell 中完成以下操作:
- 创建一本名为 "Python Crash Course" 的书,作者为 "Eric Matthes",ISBN 为 "978-1593276034"。
- 查询所有作者名为 "Eric Matthes" 的书籍。
- 将这本书的出版日期更新为 "2019-05-03"。
- 查询 ISBN 以 "978" 开头的书籍(提示:使用
startswith查找)。
练习三:关联模型
在 library 应用中,修改或添加模型,实现:
- 定义一个
Publisher(出版社) 模型,包含name和location。 - 在
Book模型中添加一个字段publisher,使其与Publisher建立"多对一"的关系(即一个出版社可以出版多本书)。
常见错误
- 忘记运行迁移命令:只修改了
models.py,但没有执行makemigrations和migrate。数据库结构不会改变,程序会报错(如OperationalError: no such table)。 - 字段类型选择错误:例如,用
CharField存储用户年龄(应使用IntegerField),或给CharField忘记设置max_length参数。 - 查询过滤条件写错:ORM 的过滤语法是
field__lookuptype=value(双下划线)。例如,过滤价格大于100是price__gt=100,而不是price>100。常用查找类型有:exact,iexact,contains,gt,lt,gte,lte,in,startswith等。 - 误解
ForeignKey的on_delete选项:on_delete决定了当关联的外键对象(如作者)被删除时,当前对象(如文章)该如何处理。CASCADE是级联删除,PROTECT是阻止删除,SET_NULL是设为空(需要设置null=True)。选错可能导致数据意外丢失或删除失败。 - 忘记调用
save()方法:创建新对象 (obj = Model(...)) 或修改现有对象属性后,必须调用obj.save()才能将更改持久化到数据库。
小结
- 模型(Model) 是 Django 中定义数据库表结构的 Python 类,每个类对应一张数据库表,类属性对应表的列(字段)。
- ORM(对象关系映射) 允许你通过操作 Python 对象来完成数据库的增删改查(CRUD),无需直接编写 SQL。
- 定义模型后,必须运行
makemigrations和migrate命令来同步数据库结构。 - 主要的 ORM 操作:
- 创建:
obj = Model(...); obj.save() - 查询:
Model.objects.all(),Model.objects.get(...),Model.objects.filter(...) - 更新:
obj.field = new_value; obj.save()或Model.objects.filter(...).update(...) - 删除:
obj.delete()
- 创建:
- 使用
ForeignKey等字段定义模型之间的关系,并注意on_delete参数的选择。 - 定义
__str__方法可以让你的对象在调试和管理界面中显示得更友好。