Django ForeignKey 外键详解:on_delete、related_name 与保存机制

Cora
Cora
发布时间:2026-10-15| 4人浏览过
原创

本文深入解析 Django 模型中 ForeignKey 外键的核心用法。详细讲解 on_delete 参数的五种删除策略(CASCADE、PROTECT 等),说明 related_name 和 related_query_name 在反向查询中的区别与应用,并演示如何通过对象实例或 ID 保存外键字段,帮助开发者规范数据库关联设计。

本文档主要介绍 Django 框架中 Model 外键(ForeignKey)的处理机制及相关操作方法。

外键属于一对多字段类型,用于定义两张数据表之间的关联关系。

本文主要内容目录如下:

  • on_delete 参数
  • related_name 属性
  • related_query_name 属性
  • 外键字段的保存方式

1、on_delete 参数详解

假设存在两个 Django 应用,分别命名为 app1 和 app2。

在 app1 中定义一个名为 App1 的 Model。

在 app2 中定义一个名为 App2 的 Model。

# app1/models.py
class App1(models.Model):
    app2 = models.ForeignKey("app2.App2", on_delete=models.CASCADE)
# app2/models.py
class App2(models.Model):
    pass

在设置 ForeignKey 时,on_delete 参数用于指定当被关联的外键数据被删除时,当前 Model 数据的处理行为。

以上述两个 Model 为例,当 App2 中的某条数据被删除时,App1 中关联该数据的记录将依据 on_delete 策略进行处理。

常见的处理策略包括以下几种:

CASCADE(级联删除):当 App2 的数据被删除时,App1 中关联该数据的所有记录也将被同时删除。

PROTECT(保护模式):如果 App2 的数据被 App1 关联,则禁止删除该 App2 数据,会抛出 ProtectedError 异常。

SET_NULL(置空):当 App2 的数据被删除时,App1 中关联该数据的字段值将被设置为 NULL。注意,这要求该外键字段允许为 null。

DO_NOTHING(无操作):原数据不会有任何变更,即 App2 的某条数据被删除后,App1 中的引用依然保留。

需要注意的是,DO_NOTHING 通常不推荐在生产环境中使用。因为如果后续代码访问 App1 中该字段,尝试获取已删除的 App2 数据时,会引发数据库错误。

2、related_name 属性解析

ForeignKey 拥有一个名为 related_name 的属性,用于定义从相关对象反向访问当前对象的名称。该属性主要用于反向查询时的标识展示。如果未单独设置 related_query_name,则默认使用 related_name 的值。

特别注意:当同一个 Class 中存在两个或多个字段都指向另一个 Model 的外键时,必须为每个外键设置不同的 related_name,以区分不同的反向访问路径。

具体示例如下:

class Entry(models.Model):
    blog_old = models.ForeignKey(Blog, related_name='old_entry')
    blog_new = models.ForeignKey(Blog, related_name='new_entry')

3、related_query_name 属性解析

该字段主要用于反向过滤器(reverse filter)的搜索命名。若未单独赋值,系统将默认使用 related_name 的值。

为了说明反向过滤器的功能,参考以下两个 Model 的定义:

class Blog(models.Model):
    pass

class Entry(models.Model):
    blog = models.ForeignKey(Blog)

假设现在数据库中已存在一条 Blog 数据。

blog_1 = Blog.objects.get(id=1)

若希望获取 Entry 表中 blog 字段值为 blog_1 的所有记录,常规做法如下:

entry_list = Entry.objects.filter(blog=blog_1)

由于 blog 字段是外键,我们可以利用 Django 提供的反向过滤器功能来实现:

entry_list = blog_1.entry_set.all()

上述即为反向过滤器的基本用法,即使用关联 Model 名称的小写形式加上 '_set' 后缀来操作,这是 Django 的默认固定用法。

如果在定义外键时设置了 related_query_name 字段,则可以废弃 'model_name_set' 的默认用法,直接通过设置的 related_query_name 进行反向查询。例如 Entry 定义如下:

class Entry(models.Model):
    blog = models.ForeignKey(Blog, related_name="entries")

此时,若未单独设置 related_query_name 的值,系统将自动使用 related_name 的值。使用反向过滤器的方法如下:

entry_list = blog_1.entries.all()

4、外键字段的保存机制

首先介绍外键字段在 Django Model 定义与底层数据库结构中的表现形式。

在 Model 代码中,以 Entry 为例,关键的外键字段通常直接命名为 'blog'。

但在实际的数据库结构中,查看表结构时会发现该字段名为 'blog_id',即字段名加上 '_id' 后缀。

假设获取了一个 Entry 实例,变量名为 entry_obj。

entry_obj = Entry.objects.get(id=1)

当输出 entry_obj.blog 时,返回的是一个 Blog 的实例对象(object)。

而当输出 entry_obj.blog_id 时,返回的是一个整型(int)的主键 ID 值。

那么,如何为 Entry 实例保存 blog 字段呢?如果已有一个 Blog 实例 blog_1,可以直接赋值:

entry_obj.blog = blod_1
entry_obj.save()

如果已知某个 Blog 的主键 ID 为 blog_id,也可以通过 ID 进行赋值:

entry_obj.blog_id = blod_id
entry_obj.save()

至此,关于 Django 中 ForeignKey 外键的介绍与使用已讲解完毕。如需了解更多 Django 外键相关内容,建议查阅本站过往文章或继续浏览后续教程,感谢支持!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。