概述

本来是打算写Cheat Sheet的,但是又加入一点知识讲解,所以称作README好了。
本文假设你已经掌握对象关系相关的基础知识。

正向访问与反向访问

首先必需要明白的是正向访问和反向访问的概念,彻底明白后,在访问关联对象时就不会蒙圈了。

假设在模型A中定义了关系字段指向了模型B。

  1. class A(models.Model):
  2. b = models.ManyToManyField(to='B')

那么A访问B就是正向访问,B访问A就是反向访问

需求模拟

假设我们要写一个企业内部的资产管理系统,每个应用我们用Node来表示,一个应用节点可能涉及很多信息,所以增加一个NodeExtension模型用来记录应用的扩展信息(例如描述、负责人、部门等信息);同一个应用,公司为了区分开发环境配置了不同的域名例如ehr、preehr、testehr;每个应用节点的负责人可能会有多个,每个负责人也可能同时负责多个应用。

Node表:用来表示应用节点,
NodeExtension表,用来表示应用节点的扩展信息,与Node表是一对一的关系,
Domain表:用来表示域名,与Node表是多对一的关系,
Owner表:用来表示负责人,与NodeExtension表是多对多的关系。

一对一

在Django中使用OneToOneField来表示一个一对一的关系。

  1. class Node(models.Model):
  2. pass
  1. class NodeExtension(models.Model):
  2. node = models.OneToOneField(to="Node", on_delete=models.CASCADE, null=True)

image.png

查询

在访问一对一的关联对象时,可以当作普通的字段(非关联的对象)对待。

正向访问

NodeExtension实例访问Node字段,使用声明的字段名

  1. NODE_EXTENSION.node

反向访问

Node实例访问NodeExtension字段,使用对方表名(全部小写)

  1. NODE.nodeextension

多对一

在Django中使用ForeignKey来表示多对一的关系,且只能在多的那一方进行使用

  1. class Domain(models.Model):
  2. node = models.ForeignKey(to="Node", on_delete=models.SET_NULL, null=True, blank=True)

image.png

查询

正向访问

Domian实例访问Node字段,使用定义的字段名

  1. DOMAIN.node

反向访问

Node实例访问Domain字段,使用对方表名(全部小写) +_set【重要】

  1. NODE.domain_set.all()

增加

正向访问

  1. DOMAIN.node = NODE

反向访问

  1. NODE.domain_set.add(DOMAIN)
  1. NODE.domain_set.set(DOMAIN_LIST)

删除

正向访问

  1. DOMAIN.node = None

反向访问

  1. NODE.domain_set.remove(DOMAIN)
  1. NODE.domain_set.clear()

多对多

在Django中使用ManyToManyField来表示一个多对多的关系。

  1. class Owner(models.Model):
  2. pass
  1. class NodeExtension(models.Model):
  2. owners = models.ManyToManyField(to='Owner')

image.png

查询

正向访问

NodeExtension实例访问Owner字段,使用定义的字段名

  1. NODE_EXTENSION.owners.all()

反向访问

Owner实例访问NodeExtension字段,使用对方表名(全部小写) +_set【重要】

  1. OWNER.nodeextension_set.all()

增加-单条

反向访问

  1. OWNER.nodeextension_set.add()

正向访问

  1. NODE_EXTENSION.owners.add()

增加-集合

反向访问

  1. OWNER.nodeextension_set.set(NODE_EXTENSION_LIST)

正向访问

  1. NODE_EXTENSION.owners.set(OWNER_LIST)

删除-单条

反向访问

  1. OWNER.nodeextension_set.remove(NODE_EXTENSION)

正向访问

  1. NODE_EXTENSION.owners.remove(OWNER)

删除-全部

反向访问

  1. OWNER.nodeextension_set.clear()

正向访问

  1. NODE_EXTENSION.owners.clear()

操作方法 Cheat Sheet

将模型对象实例加入关联对象的集合中。

  1. add(obj)
  1. add(obj1, obj2, ...)

从关联对象的集合中删除指定的模型对象实例。

  1. remove(obj)
  1. remove(obj1, obj2, ...)

从关联对象集合删除所有对象。

  1. clear()

用模型对象实例的集合替换关联对象的集合。

  1. set(objs)

自定义反向访问的字段名

在关系字段中使用related_name参数来指定反向访问的字段名

  1. class Domain(models.Model):
  2. name = models.CharField(max_length=32)
  3. node = models.ForeignKey(to='Node', on_delete=models.SET_NULL,
  4. null=True, blank=True, related_name='domains')

正向访问

  1. DOMAIN.node

反向访问

  1. NDOE.domains

官方文档

https://docs.djangoproject.com/zh-hans/3.2/ref/models/relations/