66·模块十三:Web开发基础进阶

Django 模型(Models)与 ORM

djangomodelsorm

第 66 课:Django 模型(Models)与 ORM

学习目标

完成本课学习后,你将能够:

  1. 理解 Django 模型(Model)的基本概念及其与数据库表的关系。
  2. 掌握使用 Django 模型类定义数据表结构(字段类型、选项)。
  3. 学会使用 Django ORM(对象关系映射)进行数据的创建(Create)、查询(Read)、更新(Update)和删除(Delete),即 CRUD 操作。
  4. 初步了解模型之间的关系(如一对多关系)的定义。

核心概念

在上一课中,我们创建了第一个 Django 项目和应用。现在,我们将学习如何使用模型来定义应用的数据结构。

1. 模型(Model)是什么? 想象一下,你在设计一个图书馆管理系统。你需要记录"图书"和"作者"的信息。在数据库里,你会创建"Books"表和"Authors"表。在 Django 中,模型(Model)就是用 Python 代码来定义这些数据库表结构的蓝图。每个模型类对应数据库中的一张表,类中的属性(字段)对应表中的列。

2. ORM 是什么? ORM 全称是 Object-Relational Mapping(对象关系映射)。你可以把它理解为一个"翻译官"。它让你可以用 Python 的代码(操作 Python 对象)来与数据库进行交互,而不需要直接编写 SQL 语句。当你创建、查询、修改或删除一个模型实例(数据库表中的一行记录)时,ORM 会自动将其翻译成对应的 SQL 语句并执行。

3. 主要步骤

  1. 在应用的 models.py 文件中定义你的模型。
  2. 运行数据库迁移(Migrate)命令,让 Django 根据你的模型定义在数据库中创建(或修改)真实的表。
  3. 在视图、管理命令或其他代码中,使用 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 中完成以下操作:

  1. 创建一本名为 "Python Crash Course" 的书,作者为 "Eric Matthes",ISBN 为 "978-1593276034"。
  2. 查询所有作者名为 "Eric Matthes" 的书籍。
  3. 将这本书的出版日期更新为 "2019-05-03"。
  4. 查询 ISBN 以 "978" 开头的书籍(提示:使用 startswith 查找)。

练习三:关联模型library 应用中,修改或添加模型,实现:

  • 定义一个 Publisher (出版社) 模型,包含 namelocation
  • Book 模型中添加一个字段 publisher,使其与 Publisher 建立"多对一"的关系(即一个出版社可以出版多本书)。

常见错误

  1. 忘记运行迁移命令:只修改了 models.py,但没有执行 makemigrationsmigrate。数据库结构不会改变,程序会报错(如 OperationalError: no such table)。
  2. 字段类型选择错误:例如,用 CharField 存储用户年龄(应使用 IntegerField),或给 CharField 忘记设置 max_length 参数。
  3. 查询过滤条件写错:ORM 的过滤语法是 field__lookuptype=value(双下划线)。例如,过滤价格大于100是 price__gt=100,而不是 price>100。常用查找类型有:exact, iexact, contains, gt, lt, gte, lte, in, startswith 等。
  4. 误解 ForeignKeyon_delete 选项on_delete 决定了当关联的外键对象(如作者)被删除时,当前对象(如文章)该如何处理。CASCADE 是级联删除,PROTECT 是阻止删除,SET_NULL 是设为空(需要设置 null=True)。选错可能导致数据意外丢失或删除失败。
  5. 忘记调用 save() 方法:创建新对象 (obj = Model(...)) 或修改现有对象属性后,必须调用 obj.save() 才能将更改持久化到数据库。

小结

  • 模型(Model) 是 Django 中定义数据库表结构的 Python 类,每个类对应一张数据库表,类属性对应表的列(字段)。
  • ORM(对象关系映射) 允许你通过操作 Python 对象来完成数据库的增删改查(CRUD),无需直接编写 SQL。
  • 定义模型后,必须运行 makemigrationsmigrate 命令来同步数据库结构。
  • 主要的 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__ 方法可以让你的对象在调试和管理界面中显示得更友好。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「Django 视图(Views)与 URL 路由」 以巩固所学知识。