概述
本来是打算写Cheat Sheet的,但是又加入一点知识讲解,所以称作README好了。
本文假设你已经掌握对象关系相关的基础知识。
正向访问与反向访问
首先必需要明白的是正向访问和反向访问的概念,彻底明白后,在访问关联对象时就不会蒙圈了。
假设在模型A中定义了关系字段指向了模型B。
class A(models.Model):
b = models.ManyToManyField(to='B')
需求模拟
假设我们要写一个企业内部的资产管理系统,每个应用我们用Node来表示,一个应用节点可能涉及很多信息,所以增加一个NodeExtension模型用来记录应用的扩展信息(例如描述、负责人、部门等信息);同一个应用,公司为了区分开发环境配置了不同的域名例如ehr、preehr、testehr;每个应用节点的负责人可能会有多个,每个负责人也可能同时负责多个应用。
Node表:用来表示应用节点,
NodeExtension表,用来表示应用节点的扩展信息,与Node表是一对一的关系,
Domain表:用来表示域名,与Node表是多对一的关系,
Owner表:用来表示负责人,与NodeExtension表是多对多的关系。
一对一
在Django中使用OneToOneField来表示一个一对一的关系。
class Node(models.Model):
pass
class NodeExtension(models.Model):
node = models.OneToOneField(to="Node", on_delete=models.CASCADE, null=True)
查询
在访问一对一的关联对象时,可以当作普通的字段(非关联的对象)对待。
正向访问
NodeExtension实例访问Node字段,使用声明的字段名
NODE_EXTENSION.node
反向访问
Node实例访问NodeExtension字段,使用对方表名(全部小写)
NODE.nodeextension
多对一
在Django中使用ForeignKey来表示多对一的关系,且只能在多的那一方进行使用。
class Domain(models.Model):
node = models.ForeignKey(to="Node", on_delete=models.SET_NULL, null=True, blank=True)
查询
正向访问
Domian实例访问Node字段,使用定义的字段名
DOMAIN.node
反向访问
Node实例访问Domain字段,使用对方表名(全部小写) +_set
【重要】
NODE.domain_set.all()
增加
正向访问
DOMAIN.node = NODE
反向访问
NODE.domain_set.add(DOMAIN)
NODE.domain_set.set(DOMAIN_LIST)
删除
正向访问
DOMAIN.node = None
反向访问
NODE.domain_set.remove(DOMAIN)
NODE.domain_set.clear()
多对多
在Django中使用ManyToManyField来表示一个多对多的关系。
class Owner(models.Model):
pass
class NodeExtension(models.Model):
owners = models.ManyToManyField(to='Owner')
查询
正向访问
NodeExtension实例访问Owner字段,使用定义的字段名
NODE_EXTENSION.owners.all()
反向访问
Owner实例访问NodeExtension字段,使用对方表名(全部小写) +_set
【重要】
OWNER.nodeextension_set.all()
增加-单条
反向访问
OWNER.nodeextension_set.add()
正向访问
NODE_EXTENSION.owners.add()
增加-集合
反向访问
OWNER.nodeextension_set.set(NODE_EXTENSION_LIST)
正向访问
NODE_EXTENSION.owners.set(OWNER_LIST)
删除-单条
反向访问
OWNER.nodeextension_set.remove(NODE_EXTENSION)
正向访问
NODE_EXTENSION.owners.remove(OWNER)
删除-全部
反向访问
OWNER.nodeextension_set.clear()
正向访问
NODE_EXTENSION.owners.clear()
操作方法 Cheat Sheet
将模型对象实例加入关联对象的集合中。
add(obj)
add(obj1, obj2, ...)
从关联对象的集合中删除指定的模型对象实例。
remove(obj)
remove(obj1, obj2, ...)
从关联对象集合删除所有对象。
clear()
用模型对象实例的集合替换关联对象的集合。
set(objs)
自定义反向访问的字段名
在关系字段中使用related_name参数来指定反向访问的字段名
class Domain(models.Model):
name = models.CharField(max_length=32)
node = models.ForeignKey(to='Node', on_delete=models.SET_NULL,
null=True, blank=True, related_name='domains')
正向访问
DOMAIN.node
反向访问
NDOE.domains
官方文档
https://docs.djangoproject.com/zh-hans/3.2/ref/models/relations/