多表操作
1. 表之间存在三种关系: 多对一, 一对一, 多对多, 如何确定表与表之间的关系?
左表<------------------------------->右表 # 步骤一:先分析 #分析1、先站在左表的角度 是否左表的多条记录可以对应右表的一条记录 #分析2、再站在右表的角度去找 是否右表的多条记录可以对应左表的一条记录 # 步骤二:后确定关系 # 多对一 如果只有"分析1"成立,那么可以确定两张表的关系是:左表多对一右表,关联字段应该创建在左表中,然后foreign key 右表一个字段(通常是id) 如果只有"分析2"成立,那么可以确定两张表的关系是:右表多对一左表,关联字段应该创建在右表中,然后foreign key 左表一个字段(通常是id) # 一对一 如果"分析1"和"分析2"都不成立,而是左表的一条记录唯一对应右表的一条记录,反之亦然。这种情况很简单,就是在左表foreign key右表的基础上,将左表的关联字段设置成unique即可 # 多对多 如果"分析1"和"分析2"同时成立,则证明这两张表是一个双向的多对一,即多对多,需要创建一张单独的新表来专门存放二者的关系,关联字段应该创建在新表中,然后在新表中
2. 举列说明
书籍表 : book
出版社表: publish
作者表: author
作者详情表: author_detail
2.1 book与publish
找关系
左表(app01_book)<------------------------------->右表(app01_publish) # 步骤一: #分析1、先站在左表的角度 左表的多条记录代表多版本书籍,右表的一条记录代表一个出版社,多本书籍对应同一个出版社 ✔️ #分析2、再站在右表的角度去找 右表的多条记录代表多个出版社,左表的一条记录代表一本书,多个出版社不能出版同一本书 ✘ # 步骤二:后确定关系 # 多对一 只有"分析1"成立,那么可以确定两张表的关系是:左表(app01_book)多对一右表(app01_publish),关联字段应该创建在左表(app01_book)中,然后foreign key 右表
SQL语句
# 1、由于foreign key的影响,必须先创建被关联表 CREATE TABLE app01_publish ( id INT PRIMARY KEY auto_increment, name VARCHAR (20) ); # 2、才能创建出关联表 CREATE TABLE app01_book ( id INT PRIMARY KEY auto_increment, title VARCHAR (20), price DECIMAL (8, 2), pub_date DATE, publish_id INT, # 新增关联字段 FOREIGN KEY (publish_id) REFERENCES app01_publish (id) ON UPDATE CASCADE ON DELETE CASCADE );
2.2 author与author_detail
找关系
左表(app01_author)<------------------------------->右表(app01_authordetail) 一个作者唯一对应一条自己的详情信息,反之亦然,所以两张表是一对一的关系。在左表中新增关联字段并添加unique约束,然后foreign key右表
SQL语句
# 1、由于foreign key的影响,必须先创建被关联表 CREATE TABLE app01_authordetail ( id INT PRIMARY KEY auto_increment, tel VARCHAR (20) ); # 2、才能创建出关联表 CREATE TABLE app01_author ( id INT PRIMARY KEY auto_increment, name VARCHAR (20), age INT, authordetail_id INT UNIQUE, # 新增关联字段,并添加唯一性约束unique FOREIGN KEY (authordetail_id) REFERENCES app01_authordetail (id) ON UPDATE CASCADE ON DELETE CASCADE );
2.3 book与author
找关系
左表(app01_book)<------------------------------->右表(app01_author) # 步骤一: #分析1、先站在左表的角度 左表的多条记录代表多版本书籍,右表的一条记录代表一个作者,多本书籍可以由同一个作者编写 ✔️ #分析2、再站在右表的角度去找 右表的多条记录代表多个作者,左表的一条记录代表一本书,多个作者可以合作编写同一本书 ✔️ # 步骤二:后确定关系 # 多对多 "分析1"和"分析2"同时成立,证明这两张表是多对多的关系,需要创建一张单独的新表来专门存放二者的关系,关联字段应该创建在新表中,然后在新表中分别foreign key两张表
SQL语句
# 1、创建被关联表一:app01_book,例1中已创建 # 2、创建被关联表二:app01_author,例2中已创建 # 3、创建新表,存放app01_book于app01_author的关联关系 CREATE TABLE app01_book_authors ( id INT PRIMARY KEY auto_increment, book_id INT, # 新增关联字段,用来关联表app01_book author_id INT, # 新增关联字段,用来关联表app01_author FOREIGN KEY (book_id) REFERENCES app01_book (id) ON UPDATE CASCADE ON DELETE CASCADE, FOREIGN KEY (author_id) REFERENCES app01_author (id) ON UPDATE CASCADE ON DELETE CASCADE );
3. 创建模型(models.py)
from django.db import models # 表app01_publish class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=20) # 表app01_book class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=20) price = models.DecimalField(max_digits=8, decimal_places=2) pub_date = models.DateField() # 表app01_book多对一表app01_publish,参数to指定模型名,参数to_field指定要关联的那个字段 publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) # 我们自己写sql时,针对书籍表与作者表的多对关系,需要自己创建新表,而基于django的orm,下面这一行代码可以帮我们自动创建那张关系表 authors=models.ManyToManyField(to='Author') # 变量名为authors,则新表名为app01_book_authors,若变量名为xxx,则新表名为app01_book_xxx # 表app01_author class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=20) age = models.IntegerField() # 表app01_author一对一表app01_authordetail author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE) # 表app01_authordetail class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) tel = models.CharField(max_length=20)
4. 添加 删除 修改记录
4.1 添加
4.1.1 多对一: book与publish
# 需求:书籍(葵花宝典、菊花宝典、桃花宝典)都是在北京出版社出版的 # 1、先通过模型Publish从出版社表app01_publish查出北京出版社 publish_obj=Publish.objects.filter(name='北京出版社').first() # 上述代码也可以简写为:publish_obj=Publish.objects.get(name='北京出版社') # 2、再通过模型Book往书籍表app01_book里插入三本书籍与出版社的对应关系 # 方式一:使用publish参数指定关联 book_obj1=Book.objects.create(title='葵花宝典',price=2000,pub_date='1985-3-11',publish=publish_obj) book_obj2=Book.objects.create(title='菊花宝典',price=3000,pub_date='1990-1-21',publish=publish_obj) book_obj3=Book.objects.create(title='桃花宝典',price=4000,pub_date='1991-1-23',publish=publish_obj) # 方式二:使用publish_id参数指定关联 book_obj1=Book.objects.create(title='葵花宝典',price=2000,pub_date='1985-3-11',publish_id=publish_obj.nid) book_obj2=Book.objects.create(title='菊花宝典',price=3000,pub_date='1990-1-21',publish_id=1) # 在已经出版社id的情况下,可以直接指定 book_obj3=Book.objects.create(title='桃花宝典',price=4000,pub_date='1991-1-23',publish_id=1) # 注意:无论方式一还是方式二得到的书籍对象book_obj1、book_obj2、book_obj3 # 都可以调用publish字段来访问关联的那一个出版社对象 # 都可以调用publish_id来访问关联的那一个出版社对象的nid print(book_obj1.publish,book_obj1.publish_id) print(book_obj2.publish,book_obj2.publish_id) print(book_obj3.publish,book_obj3.publish_id) # 三本书关联的是同一个出版社,所以输出结果均相同
4.1.2 一对一: author与author_detail
# 需求:插入三个作者,并与作者详情表一一对应 # 由于作者详情表我们已经事先创建好记录,所以只需要往作者表插入记录即可 # 方式一:需要事先过滤出作者详情的对象,然后通过模型Author的字段author来指定要关联的作者详情对象(略) # 方式二:确定作者详情对象的id,然后通过模型Author通过字段author_id来指定关联关系, Author.objects.create(name='egon',age=18,author_detail_id=1) Author.objects.create(name='kevin',age=38,author_detail_id=2) Author.objects.create(name='rose',age=28,author_detail_id=3)
4.1.3 多对多: book与author
# 我们参照物理表app01_book_authors制定需求,需要创建如下关系 # 1、葵花宝典的作者为:egon、kevin # 2、菊花宝典的作者为:egon、kevin、rose # 3、桃花宝典的作者为:egon、kevin # 4、玉女心经的作者为:kevin、rose # 5、玉男心经的作者为:kevin # 6、九阴真经的作者为:egon、rose # 需要创建出上述关系,具体做法如下 # 1、先获取书籍对象 book_obj1=Book.objects.get(title='葵花宝典') book_obj2=Book.objects.get(title='菊花宝典') book_obj3=Book.objects.get(title='桃花宝典') book_obj4=Book.objects.get(title='玉女心经') book_obj5=Book.objects.get(title='玉男心经') book_obj6=Book.objects.get(title='九阴真经') # 2、然后获取作者对象 egon=Author.objects.get(name='egon') kevin=Author.objects.get(name='kevin') rose=Author.objects.get(name='rose') # 3、最后依次创建上述关系:在原生SQL中多对多关系涉及到操作第三张关系表,但是在ORM中我们只需要操作模型类Book下的字段author即可 book_obj1.authors.add(egon,kevin) book_obj2.authors.add(egon,kevin,rose) book_obj3.authors.add(egon,kevin) book_obj4.authors.add(kevin,rose) book_obj5.authors.add(kevin) book_obj6.authors.add(egon,rose)
4.2 查询
正向和反向查询
例如: book与publish, 关联字段在book表中
# 当以Book为基表时,称之为正向查询 Book(基表)-------正向---------->Publish # 当以Publish为基表时,称之为反向查询 Book<-------反向----------Publish(基表)
4.2.1 基于对象的跨表查询(两张表)
一对一查询
正向查询, 按关联字段: author_detail
# 需求:查询作者egon的手机号 # 1、先取出作者对象 egon=Author.objects.filter(name='egon').first() # 2、正向查询:根据作者对象下的关联字段author_detail取到作者详情 print(egon.author_detail.tel) # 输出:18611312331
反向查询, 按表名小写: author
# 需求:查询手机号为'18611312331'的作者名 # 1、先取出作者的详情对象 tel=AuthorDetail.objects.filter(tel='18611312331').first() # 2、反向查询:根据小写的模型名author取到作者对象 print(tel.author.name) # 输出:egon
多对一
正向查询,按关联字段:publish
# 需求:查询葵花宝典的出版社名字 # 1、先取书籍对象 book_obj=Book.objects.filter(title='葵花宝典').first() # 2、正向查询:根据书籍对象下的关联字段publish取到出版社 print(book_obj.publish.name) # 输出:北京出版社
反向查询,按模型名(小写)_set:book_set
# 需求:查询北京出版社都出版的所有书籍名字 # 1、先取出出版社对象 publish_obj=Publish.objects.filter(name='北京出版社').first() # 2、反向查询:根据book_set取到所有的书籍 book_objs=publish_obj.book_set.all() print([book_obj.title for book_obj in book_objs]) # 输出:['葵花宝典', '菊花宝典', '桃花宝典']
多对多查询同多对一
4.2.2 基于双下划线的跨表查询
一对一查询
正向查询,按关联字段+双下划线:author_detail__
# 需求:查询作者egon的手机号 # 注意values()中的参数是:关联字段名__要取的那张被关联表中的字段 res = Author.objects.filter(name='egon').values('author_detail__tel').first() print(res['author_detail__tel']) # {'author_detail__tel': '18611312331'} # 注意:基于双下划线的跨表查询会被django的orm识别为join操作,所以上述代码相当于如下sql,后续案例均是相同原理,我们不再累述 select app01_authordetail.tel from app01_author inner join app01_authordetail on app01_author.author_detail_id = app01_authordetail
反向查询,按模型名(小写)+双下划线:author__
# 需求:查询手机号为'18611312331'的作者名 # 注意values()中的参数是:小写的模型名__要取的那张被关联表中的字段 res=AuthorDetail.objects.filter(tel='18611312331').values('author__name').first() print(res) # {'author__name': 'egon'}
多对一和多对多查询同一对一查询一样
来源:https://www.cnblogs.com/zhuangshenhao/p/12104479.html