侧边栏壁纸
博主头像
我的学习心得 博主等级

行动起来,活在当下

  • 累计撰写 223 篇文章
  • 累计创建 60 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录
DRF

Django 通用外键

Administrator
2024-02-02 / 0 评论 / 0 点赞 / 1023 阅读 / 0 字

models.ForeignKey() 可以使当前模型与单个其他模型建立外键关系,例如我们通过 creator 字段记录资源的创建者:

class Resource(models.Model):
    ...
    creator = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)

如果我们需要通过某个字段与多个模型建立外键关系,就需要用到 通用外键

from django.contrib.contenttypes.fields import GenericForeignKey

通用外键是一种特殊的外键,它允许模型与多个其他模型建立关联,而不需要在定义字段时明确关联的模型。

GenericForeignKey 是一个虚拟字段(它只存在于 Python 内存中,不存在于数据库中),它主要有两个参数:

  • ct_field: 关联的模型,通常定义 content_type 字段外键关联到内置的 ContentType 模型
  • fk_field: 关联的实例,通常定义一个 object_id,类型是 PositiveIntegerField
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey

class Resource(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")

content_object 并不存在于数据库中,但是我们可以在 ORM 中通过 resource.content_object 取出对应的实例对象。

django.contrib.contenttypes.models.ContentType 用于存储模型的元数据。

通常与 GenericForeignKey 一起使用,用于创建通用外键,动态绑定模型。

常见的 ContentType 实例方法:

  • get_for_model(model): 查询模型类的 ContentType 实例
  • get_object_for_this_type(**kwargs): 基于指定的 ContentType 实例查询关联的模型实例
  • model: 查询当前 ContentType 实例关联的模型类
  • app_label: 查询当前 ContentType 实例关联的模型所属的应用名称

到此为止,resource.content_object 可以取出关联的模型实例。

但是我们怎么通过关联的模型实例取出所有的 Resource 实例呢?

例如我们定义了另一个模型 Module,我们期望以 module.resources 的形式取出 Module 实例关联的所有 Resource 实例。

我们还需要在 Module 模型上定义获取 reosurces 的方法:

from django.contrib.contenttypes.fields import GenericRelation

class Module(models.Model):
    resources = GenericRelation(Resource)

resources 也是一个虚拟字段,此时 module.resources 是一个查询集对象。

综上:

  • 使用通用外键的模型需要
    • 定义 content_type 字段并外键关联到 ContentType 模型
    • 定义 object_id 字段,类型为 PositiveIntegerField
    • 定义content_object 虚拟字段,通过 GenericForeignKey 配合上面的 content_type 和 object_id 动态关联其他模型的实例
  • 反向查询关联的实例需要通过 GenericRelation 声明虚拟字段
0

评论区