多对多(ManyToManyField)

假设每个小孩都能喜欢一种或多种颜色,某种颜色也能把一个或多个小孩喜欢,这样颜色和小孩之间就是多对多关系,Django 中的一对多关系用 ManyToManyField 来实现。

from django.db import models

class Colors(models.Model):
    colors = models.CharField(max_length=10)

# 多对多
class Child(models.Model):
    child_name = models.CharField(max_length = 10)   # 姓名  
    favor = models.ManyToManyField('Colors')    # 喜好,与颜色表为多对多




查询数据

子表查询母表:

# 查询小明喜欢的所有颜色

# 方法一

child_obj = Child.objects.get(child_name="小明")
child_obj.favor.all()

>>> , ]>
# 方法二

Colors.objects.filter(child__child_name="小明")

>>> , ]>

母表查询子表

# 查询哪些人喜欢蓝色

# 方法一

color_obj = Colors.objects.get(colors="blue")
color_obj.child_set.all()

>>> , ]>
# 方法二

color_obj = Colors.objects.get(colors="blue")
Child.objects.filter(favor=color_obj)

>>> , ]>


# 方法二简便写法

Child.objects.filter(favor__colors="blue")
>>> , ]>
# 方法三

color_id = Colors.objects.get(colors="blue").id 
Child.objects.filter(favor=color_id)

>>> , ]>




添加和修改数据

添加子表关联关系

# 创建一个新的小孩“小周”,并让他喜欢所有颜色

# 方法一

child_obj = Child.objects.create(child_name="小周")
colors_obj = Colors.objects.all()
child_obj.favor.add(*colors_obj)
# 方法二

child_obj = Child.objects.get(child_name="小周")
colors_obj = Colors.objects.all()
child_obj.favor = colors_obj
child_obj.save()
# 让小周喜欢红和蓝两种颜色

# 方法一

child_obj = Child.objects.get(child_name="小周")
colors_obj = Colors.objects.filter(colors__in=["red","blue"])
child_obj.favor.clear() # 清空小周原来喜欢的颜色
child_obj.favor.add(*colors_obj)
# 方法二

child_obj = Child.objects.get(child_name="小周")
colors_obj = Colors.objects.filter(colors__in=["red","blue"])
child_obj.favor = colors_obj
child_obj.save()

添加母表关联关系

# 在喜欢蓝色的人里面加上“小刘”

child_obj = Child.objects.get(child_name="小刘")
colors_obj = Colors.objects.get(colors="blue")
colors_obj.child_set.add(child_obj)
# 让所有人都喜欢蓝色

child_obj = Child.objects.all()
colors_obj = Colors.objects.get(colors="blue")
colors_obj.child_set.add(*child_obj)

关于 _set 写法,只有子表才有 "子表名小写_set" 的写法,得到的是一个 QuerySet 集合,后边可以接 .add() / .remove() / .update() / .delete() / .clear() 方法。




删除数据

删除多对多表关系

# 删除子表与母表关联关系
# 让“小明”不喜欢任何颜色

# 方法一

child_obj = Child.objects.get(child_name="小明")
child_obj.favor = ''
child_obj.save()
# 方法二

child_obj = Child.objects.get(child_name="小明")
colors_obj = Colors.objects.all()
child_obj.favor.remove(*colors_obj)
# 方法三

child_obj = Child.objects.get(child_name="小明")
child_obj.favor.clear()
# 删除母表与子表关联关系
# 让所有人不再喜欢蓝色

# 方法一

child_obj = Child.objects.all()
colors_obj = Colors.objects.get(colors="blue")
colors_obj.child_set.remove(*child_obj)
# 方法二

colors_obj = Colors.objects.get(colors="blue")
colors_obj.child_set.clear()

删除多对多表数据

# 删除子表数据
# 喜欢蓝色的所有人都删掉

colors_obj = Colors.objects.get(colors="blue")
colors_obj.child_set.all().delete()  #注意有.all()
# 删除所有child
Child.objects.all().delete()

删除母表数据:

默认情况下,删除母表数据后,那么子表与颜色表是 一对一外键 关系的,子表对应数据会自动删除。

如,删除颜色“red”后,对应的“1号球”和“红色衣服”都会被删除。

如果想让与母表外键关联的子表在删除外键之后依旧可以保留子表数据,需要子表建表时加入以下字段:

class Clothes(models.Model):
    # clothes_color 字段可为空,如果外键被删后,子表数据此字段置空而不是直接删除这条数据
    # 同理也可以 SET_DEFAULT,需要此字段有默认值
    clothes_color = models.ForeignKey("Colors", null=True, on_delete=models.SET_NULL)
    description = models.CharField(max_length = 10) #描述

你可能感兴趣的:(多对多(ManyToManyField))