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

一. 多对多表ManyToManyField (ORM)

https://www.cnblogs.com/yoyoketang/p/10580253.html

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())  #返回男或

多对对案例2

# models.py

form django.db import models

class Book(models.Model):  # 表名book,django会自动使用项目名+我们定义的表名
  # 如没有自定义主键,django会自动添加一个主键,字段名id 自增
  name = models.CharField(max_length=20)  # 字段名name 类型 vachar(20)
  price = models.IntegerField()   # 字段名price 类型int
  pub_date = models.DateField()   # 字段名pub_date 类型 date (时间戳)
  publish = models.ForeighKey(‘Publish‘)  # 创建外键关联到Publish表的id字段,django会自动将该名称改为publish_id  
   # 如果这样写 publish = models.ForeighKey(Publish) 括号内无引号,则必须将Publish类放到Book类的上面
  authors = models.ManyToManyField(‘Author‘,related_name=‘xxx‘)  将book与author表做多对多关系 related_name 同一对多中的说明
  # django会自动创建一张表(book与author的中间关联表)名称为appname_book_authors

  def __str__(self):
    return self.name  # 打印实例对象时显示为self.name

#class Book_Author(models.Model):  自己创建第三张表
#  book = models.ForeignKey(‘book‘)
#  author = models.ForeignKey(‘Author‘)

class Publish(models.Model):
  name = models.CharField(max_length=32)
  city = models.CharField(max_length=32)

class Author(models.Model):
  name = models.CharField(max_length=32)
  age = models.IntegerField()

  def __str__(self):
    return self.name

多对多的添加设置删除

# views.py

from django.shortcuts import render
from app_name.models import *  # 导入models.py

def add(request):  # 增加数据的视图函数
  # 系统自己创建的第三张表使用创建对象操作
   book_obj = Book.objects.get(id=4)  # 取出id为4的书
  # book_obj.authors.all()  此时取出的是一个空的集合
  authors_obj = Author.objects.all()  # 取出所有author名称的集合
  book_obj.authors.add(*author_obj)  # 将所有作者添加到这本书中
  book_obj.authors.remove(*author_obj)  # 将所有作者从书中删除
  book_obj.authors.add(2) # 将id为2的作者添加到此书
  book.obj.authors.add([1,2])  # 将id为1和2的作者添加到此书
  book_obj.authors.remove(1) # 将id为1的作者从书中删除
   book_obj.authors.clear()  # 清除此书所有的作者
   book_obj.authors.set([2,3,4]) # 将书的作者设置为id为2,3,4的作者 (相当于重新设置)
  

   # 我们自己定义的第三张表(不常用)
  Book_Author.objects.create(book_id=2, author_id=3)
  
   obj = Book.objects.get(id=2)
   obj.book_author_set.all()[0]l.author
  

  return HttpResponse(‘xxx‘)

多对多的查询

# 怎么使用多对多查询呢?
book_obj = Book.objects.get(name=‘python‘)
print(book_obj.name)  # python
print(book_obj.authors.all())  # QuerySet  返回一个QuerySet对象,里面是author的实例集合
print(type(book_obj.authors.all()))  # <class ‘django.db.models.query.QuerySet‘>

1、查询作者id为2出的所有的书
author_obj=Author.objects.get(id=2)
author_obj.book_set.all()

2、查询三班所对应的所有老师
obj = Classes.objects.filter(name=‘三班‘).first()  从班级表取出三班
obj.m.all()  # 从三班中取所有的老师 m表示多对多关系的名称

还是通过双下划线
2、查询作者alex出的所有书
Book.objects.filter(authors__name=‘alex‘).values(‘name‘,‘price‘)

原文地址:https://www.cnblogs.com/lovershowtime/p/11361198.html

时间: 2024-11-08 03:25:35

十一 .Django 多对多表ManyToManyField (ORM)的相关文章

十二 .Django 一对多表ForeighKey(ORM)

一 . 一对多表ForeighKey(ORM) 1.创建ORM表 https://www.cnblogs.com/dangrui0725/p/9615641.html 一对多:子表从母表中选出一条数据一一对应,但母表的这条数据还可以被其他子表数据选择 共同点是在admin中添加数据的话,都会出现一个select选框,但只能单选,因为不论一对一还是一对多,自己都是“一” class Colors(models.Model): colors=models.CharField(max_length=1

Django基础之数据库与ORM

一.数据库配置 1.django默认支持sqlite,mysql, oracle,postgresql数据库. django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3 引擎名称:django.db.backends.mysql 2.在django的项目中会默认使用sqlite数据库,在settings里有如下设置: DATABASES = { 'default': { 'ENGINE': 'django.db

2019年6月14日 Web框架之Django_07 进阶操作(MTV与MVC、多对多表三种创建方式、前后端传输数据编码格式contentType、ajax、自定义分页器)

摘要 MTV与MVC 多对多表三种创建方式 ajax ,前后端传输数据编码格式contentType 批量插入数据和自定义分页器 一.MVC与MTV MVC(Model View Controller 模型-视图-控制器)是一种Web架构的模式,所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求. M

多对多表的创建方式 forms组件 session与cookie

1.多对多表的创建方式 2.forms组件3.session 与 cookie 1.多对多表的创建方式 1.全自动(推荐使用*) class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) authors = models.ManyToManyField(to='Author') class Author(m

创建多对多表关系的三种方式

创建多对多表关系的三种方式 在我们之前创建多对多表的时候,一直用的都是全自动的方式来创建第三张表的. 1.全自动(推荐使用**) 好处在于 django orm会自动帮你创建第三张关系表 但是它只会帮你创建两个表的关系字段 不会再额外添加字段 虽然方便 但是第三张表的扩展性较差 无法随意的添加额外的字段 class Book(models.Model): ... authors = models.ManyToManyField(to='Author') class Author(models.M

Django多对多关系建立及Form组件

目录 Django多对多关系 1.创建方式一全自动 2.创建方式二纯手撸 3.半自动(推荐使用) forms校验组件 使用forms组件实现注册功能 form常用字段和插件 数据校验 钩子函数 HOOK Django多对多关系 1.创建方式一全自动 class Book(models.Model): title = models.CharField(max_length=32) # 多对多关系字段 authors = models.ManyToManyField(to='Authors') cl

django的多表操作

django的多表操作 1.使用场景 在实际生产过程多,我们面对的数据纷繁复杂,此时就需要良好的数据结构设计,多表之间的约束关系为我们提供了数据管理以及查询的便利.在MYsql中我们利用外键(foreign key)来实现这样的约束关系,在django中我们通过调用相应的API来实现这样的功能. 2.创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄.作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对一的关系(

Django使用普通表单、Form、以及modelForm操作数据库方式总结

Django使用普通表单.Form.以及modelForm操作数据库主要应用于增删该查的情景下,流程通用如下,只是实现方式不一样: 进入填写表单页面: 在表单页面填写信息,并提交: 表单数据验证 验证成功,和数据库进行交互(增删改查): 验证成功,页面提示表单填写失败: 一.Django使用普通表单操作数据库 1.html代码: <form action="/add/" method="post" name="addbook"> {%

Django应用app创建及ORM

一.重要知识点回顾: 1. form表单提交数据的注意事项: 1. 是form不是from,必须要有method和action (action用来指定你的数据提交到后台哪个地方,method用来指定你提交数据的方式) 2. 所有获取用户输入的表单标签要放在form表单里面,表单标签必须要有name属性 (name属性在后台会作为key来取出对应的输入内容) 3. form表单必须要有submit按钮 (将form表单包含的所有输入信息提交至action所指向的地址) 2. GET和POST 什么