十一 .Django 多对多表ManyToManyField (ORM)

烂漫一生 提交于 2019-11-27 11:10:47

一. 多对多表ManyToManyField (ORM)

1.创建orm表

多对多手动创建第三张关系表联
# 表一
class User(models.Model):
    username=models.CharField(max_length=24,db_index=True)
    def __str__(self):
         return self.username

# 表二
class Tag(models.Model):
    title=models.CharField(max_length=24)
    def __str__(self):
         return self.title


# 自定义第三张表
class UserToTag(models.Model):
    u=models.ForeignKey(to="User")
    t=models.ForeignKey(to="Tag")
    ctime=models.DateField()    
多对多手动创建第三张关系表联合唯一# 表一
class User(models.Model):
    username=models.CharField(max_length=24,db_index=True)
    def __str__(self):
         return self.username

# 表二
class Tag(models.Model):
    title=models.CharField(max_length=24)
    def __str__(self):
         return self.title
    # m=models.ManyToManyField(     #  ManyToManyField d多对多  使用 ManyToManyField 只能在第三章表 中创建三列数
    #     to="User"  ,             # 默认和user表的主键进行管理
              
    #     )


# 自定义第三张表
class UserToTag(models.Model):
    u=models.ForeignKey(to="User")
    t=models.ForeignKey(to="Tag")
    ctime=models.DateField()    
    class Meta:  #  表示联合唯一  和 ManyToManyField 差不多
        unique_together=[    # 表达的意思就是标签和同一个人不能出现多次  就一个人对应一个标签
           ("u","t"),
        ]

ManyToManyField自动创建第三表

class Colors(models.Model):
    colors=models.CharField(max_length=10) #蓝色
    def __str__(self):
        return self.colors


class Child(models.Model):
    name=models.CharField(max_length=10)   #姓名  
    favor=models.ManyToManyField('Colors')    #与颜色表为多对多
比如有多个孩子,和多种颜色、

  每个孩子可以喜欢多种颜色,一种颜色可以被多个孩子喜欢,对于双向均是可以有多个选择 

查数据

#多对多子表查询母表,查找小明喜欢哪些颜色--返回:[<Colors: 红>, <Colors: 黄>, <Colors: 蓝>]
#与一对多子表查询母表的形式不同,因为一对多,查询的是母表的“一”;多对多,查询的是母表的“多”
#写法1:
child_obj=models.Child.objects.get(name="小明")  #写法:子表对象.子表多对多字段.过滤条件(all()/filter())
print(child_obj.favor.all())
#写法2,反向从母表入手:
print(models.Colors.objects.filter(child__name="小明")) #母表对象.filter(子表表名小写__子表字段名="过滤条件")


#多对多母表查询子表,查找有哪些人喜欢黄色--返回:[<Child: 小明>, <Child: 丫蛋>]
#与一对多母表查询子表的形式完全一致,因为查到的都是QuerySet,一对多和多对多,都是在查询子表的“多”
#写法1:
color_obj=models.Colors.objects.get(colors="黄")
print(color_obj.child_set.all())
#写法2:
print(models.Child.objects.filter(favor=models.Colors.objects.get(colors="黄")))
#写法2简便写法(推荐):
print(models.Child.objects.filter(favor__colors="黄"))  #写法:filter(子表外键字段__母表字段='过滤条件')
#写法3:
color_id=models.Colors.objects.get(colors="黄").id  #通过母表获取到颜色为红的id
print(models.Child.objects.filter(favor=color_id))  #filter得到QuerySet,写法:filter(子表外键字段=母表主键对象),此处和一对多略有不同,是子表外键字段而不是外键字段_母表主键

 增与改(增添子表或母表数据参照一对一的增,多对多重点在于关系表的对应关系变更)

#添加子表关联关系
#添加小虎并让他喜欢所有颜色
#写法1:
child_obj=models.Child.objects.create(name="小虎")  #如果是已有用户,使用.get()
colors_obj=models.Colors.objects.all()  #创建颜色表的所有颜色QuerySet对象
child_obj.favor.add(*colors_obj)  #添加对应关系,将小虎和所有颜色进行关联,写法:子表对象.子表多对多字段.add(*QuerySet对象)
#写法2:
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.all()
child_obj.favor=colors_obj
child_obj.save()
#让小虎喜欢黄色和蓝色(2种写法和上边一致,只展示一种写法)
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.filter(colors__in=["蓝","黄"])  #models默认只能用这种方式得到并集,如需更复杂的过滤逻辑,需使用模块Q
child_obj.favor.clear()  #清空小虎已经喜欢的颜色
child_obj.favor.add(*colors_obj)  #add是追加模式,如果当前小虎已经喜欢绿色,那么执行后,小虎会额外喜欢蓝,黄
#让小虎喜欢绿色(2种写法和上边一致,只展示一种写法)
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.get(colors="绿")
child_obj.favor.clear()
child_obj.favor.add(colors_obj)  #此处没有*


#添加母表关联关系
#让喜欢蓝色的人里添加小虎,可以用上边的方法,一个效果,让小虎喜欢蓝色,下边介绍反向插入(从母表入手)的写法
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.get(colors="蓝")
colors_obj.child_set.add(child_obj)  #从colors表插入小虎,写法:母表对象.子表名小写_set.add(子表对象)。 让喜欢蓝色的child_set集合添加name="小虎"
#让所有人都喜欢蓝色
children_obj=models.Child.objects.all()
colors_obj=models.Colors.objects.get(colors="蓝")
colors_obj.child_set.add(*children_obj)
#关于_set写法,是否已经有些晕了,究竟什么时候使用_set,简单记忆,只有子表才有"子表名小写_set"的写法,得到的是一个QuerySet集合,后边可以接.add(),.remove(),.update(),.delete(),.clear()
#另外备注一下,colors_obj.child_set.clear()是让所有人喜欢的颜色里去掉蓝色,colors_obj.child_set.all().delete()是删除.child_set的所有人

删:删除多对多表关系 :

#删除子表与母表关联关系
#让小虎不喜欢任何颜色
#写法1:
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.all()
child_obj.favor=''
child_obj.save()
#写法2:
child_obj=models.Child.objects.get(name="小虎")
colors_obj=models.Colors.objects.all()
child_obj.favor.remove(*colors_obj)
#写法3:
child_obj=models.Child.objects.get(name="小虎")
child_obj.favor.clear()
#其他例子参照多对多的增与改案例,这里不做举例

#删除母表与子表关联关系
#让所有人不再喜欢蓝色
#写法1:
children_obj=models.Child.objects.all()
colors_obj=models.Colors.objects.get(colors="蓝")
colors_obj.child_set.remove(*children_obj)
#写法2:
colors_obj=models.Colors.objects.get(colors="蓝")
colors_obj.child_set.clear()

删除多对多表数据: 

#删除子表数据
#喜欢蓝色的所有人都删掉
colors_obj=models.Colors.objects.get(colors="蓝")
colors_obj.child_set.all().delete()  #注意有.all()
#删除所有child
models.Child.objects.all().delete()
删除母表数据:

默认情况下,如此例中,删除“红”色,那么子表与颜色表是一对一或外键关系的,子表对应数据会自动删除,如:红球,小虎哥
与颜色表是多对多关系的话,不会自动删除喜欢红色的人,而是去掉红色已选
如果想让与母表外键关联的子表在删除外键之后依旧可以保留子表数据,需要子表建表时加入以下字段:
class Clothes(models.Model):
    color=models.ForeignKey("Colors",null=True,on_delete=models.SET_NULL))  #可为空,如果外键被删后,子表数据此字段置空而不是直接删除这条数据,同理也可以SET_DEFAULT,需要此字段有默认值
    description=models.CharField(max_length=10)  #描述 

choice

#choices相当于实现一个简化版的外键,外键的选项不能动态更新,如可选项目较少,可以采用
#先在models添加choices字段
class Child(models.Model):
    sex_choice=((0,"男"),(1,"女"))
    name=models.CharField(max_length=10)  #姓名
    favor=models.ManyToManyField('Colors')    #与颜色表为多对多
    sex=models.IntegerField(choices=sex_choice,default=0)
    def __unicode__(self):
        return self.name

#在views.py中调用
child_obj=models.Child.objects.get(name="小虎")
print(child_obj.sex)  #返回0或1
print(child_obj.get_sex_display())  #返回男或

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!