八、多表模型操作,基于对象的跨表查询,基于双下划线的跨表查询
环境:
成都创新互联是专业的钟楼网站建设公司,钟楼接单;提供网站建设、成都网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行钟楼网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
根据关系创建表
首先建立django项目,编辑models.py 文件
models.py
from django.db import models # Create your models here. class Publish(models.Model): # id 如果不写,会自动生成,名字叫做nid,并且自增 # 数据库不同,可能自动生成的id 名字也不太一样。 id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) addr = models.CharField(max_length=64) email = models.EmailField() class Author_details(models.Model): phone = models.CharField(max_length=16) sex = models.IntegerField class Author(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) # 使用了 OneToOneField 与 ForeignKey,模型表的字段,后面会自动加_id # 一对一的关系:OneToOneField authordetail_id = models.OneToOneField(to='Author_details', to_field='id') def __str__(self): return self.name class Book(models.Model): name=models.CharField(max_length=16) # 浮点型,共5位,小数部分是2位 price=models.DecimalField(max_digits=5,decimal_places=2) # to= 关联表 to_field= 关联表中的字段 ,一对多的关系使用 ForeignKey publish=models.ForeignKey(to=Publish,to_field='id') # ManyToManyField 会自动创建第三张表 多对多的关系 authors=models.ManyToManyField(to=Author) def __str__(self): return self.name
迁移数据库
makemigrations
migrate
在项目中创建Py文件,可以运行在django环境中的代码
test.py
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pro77_13.settings") import django django.setup() from app01.models import *
一、多表模型创建,一对多的增删改,与多对多增删改
在app01_publish表中添加几条数据
一对多新增数据(接上面的继续写)
test.py
# 添加一本北京出版社出版的书 # 第一种方式 # ret=Book.objects.create(name='红楼梦',price=53.4,publish_id=1) # print(ret.name) # 第二种方式,存对象Publish=出版社对象,存到数据库是一个id # pk:主键,是通过主键查找 publish=Publish.objects.filter(pk=2).first() ret=Book.objects.create(name='红楼梦',price=53.4,publish=publish) print(ret.name)
app01_book表
# 一对多修改数据
test.py
方式一:
book=Book.objects.get(pk=1) # 解释:book.publish=出版社对象 book.publish_id=2 book.save()
app01_book表:
方式二:
# 解释:book=Book.objects.filter(pk=1).update(publish=出版社对象) book=Book.objects.filter(pk=1).update(publish_id=1)
app01_book表:
多对多新增数据
首先需要在app01_author与app01_author_details表中添加数据
app01_author_details表:
app01_author表:
test.py
# 为红楼梦这本书新增一个叫lqz,egon的作者
方式一:
test.py
lqz=Author.objects.filter(name='lqz').first() egon=Author.objects.filter(name='egon').first() book=Book.objects.filter(name='红楼梦').first() # # add 添加多个对象 book.authors.add(lqz,egon)
这样就可以在中间表里看见(app01_book_authors:中间表)
方式二:
# add添加作者id book.authors.add(1,2)
# 删除 remove,可以传对象,可以传id,可以传多个,不要混着用
lqz=Author.objects.filter(name='lqz').first() egon=Author.objects.filter(name='egon').first() book=Book.objects.filter(name='红楼梦').first() book.authors.remove(lqz) # 也可以 # book.authors.remove(1,2) # clear清空所有 # book.authors.clear()
set,要传一个列表,列表内可以是 id,也可以是对象
book.authors.set([2,]) # book.authors.set([lqz,])
app01_book_authors表
总结:
1 创建多表模型(详情见代码)
#用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id
# ManyToManyField会自动创建第三张表
# *************重点
# 一对一的关系:OneToOneField
# 一对多的关系:ForeignKey
# 多对多的关系:ManyToManyField
2 添加表记录
1 一对多新增
-两种方式:
-publish=对象
-publish_id=id
2 一对多删除:同单表删除
3 一对多修改:两种方式,可以传对象,可以传id
4 一对一跟一对多一样
5 多对多:
-add ----->可以传对象,可以传id,可以传多个
-remove ----->可以传对象,可以传id,可以传多个
-clear ---->没有参数
-set ----->跟上面不一样,必须传列表,列表里面可以是对象,可以是id
二、基于对象的跨表查询
一对一:
正向 author---关联字段在author--->authordetail ------> 按字段
反向 authordetail------关联字段在author--->author -----> 按表名小写
正向查询:
lqz = Author.objects.filter(name='lqz').first() egon = Author.objects.filter(name='egon').first() book = Book.objects.filter(name='红楼梦').first() # 查询lqz作者的手机号 正向查询 # author = Author.objects.filter(name='lqz').first() # authordetail = author.authordetail_id # print(authordetail.phone)
反向查询:
lqz = Author.objects.filter(name='lqz').first() egon = Author.objects.filter(name='egon').first() book = Book.objects.filter(name='红楼梦').first() # 查询地址是 :手机号 属于哪位作者的 反向查询 authordetail=Author_details.objects.filter(phone='1385469823').first() author=authordetail.author print(author.name)
一对多:
正向 book---关联字段在book--->publish ------> 按字段
反向 publish------关联字段在book--->book -----> 按表名小写_set.all()
正向查询:查询红楼梦这本书的出版社邮箱
book=Book.objects.filter(name='红楼梦').first() # # book.publish 就是出版社对象 publish=book.publish print(publish.email)
反向查询:查询地址是北京 的出版社出版的图
publish=Publish.objects.filter(addr='北京').first() # # publish.book_set.all() 拿出所有的图书 # books=publish.book_set.all() # # 统计一下条数 books=publish.book_set.all().count() print(books)
多对多:
正向 book---关联字段在book--->author ------> 按字段.all()
反向 author------关联字段在book--->book -----> 按表名小写_set.all()
正向:查询红楼梦这本书所有的作者
book=Book.objects.filter(name='红楼梦').first() book.authors.all() #是所有的作者,是一个queryset对象,可以继续点 print(book.authors.all())
反向:查询lqz写的所有书
lqz=Author.objects.filter(name='lqz').first() books=lqz.book_set.all() print(books)
连续跨表
# 查询红楼梦这本书所有的作者的手机号
book=Book.objects.filter(name='红楼梦').first() authors=book.authors.all() for author in authors: authordetail=author.authordetail_id print(authordetail.phone)
# 基于对象的查询---是子查询也就是多次查询
在终端打印出sql语句
需要要settings.py中配置以下内容
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
test.py
book=Book.objects.filter(name='红楼梦').first()
对应的sql语句:
SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish_id` FROM `app01_book` WHERE `app01_book`.`name` = '红楼梦' ORDER BY `app01_book`.`id` ASC LIMIT 1;
在查询结果之后的又一次查询(子查询,也就是多次查询)
print(book.authors.all())
对应的sql语句:
SELECT `app01_author`.`id`, `app01_author`.`name`, `app01_author`.`addr`, `app01_author`.`authordetail_id_id` FROM `app01_author` INNER JOIN `app01_book_authors` ON ( `app01_author`.`id` = `app01_book_authors`.`author_id` ) WHERE `app01_book_authors`.`book_id` = 1 LIMIT 21;
总结:
基于对象的跨表查询
1 一对一
正向:正向查询按字段
反向:反向查询按表名小写
2 一对多
正向:正向查询按字段
反向:反向按表名小写_set.all()
3 多对多
正向:正向查询按字段
反向查询:反向按表名小写_set.all()
4******基于对象的查询,多次查询(子查询)
# 基于双下划线的查询
# 一对一
# 查询lqz作者的手机号 正向查询 跨表的话,按字段
# 以author表作为基表
ret=Author.objects.filter(name='lqz').values('authordetail_id__phone') print(ret)
# 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写
ret=Author_details.objects.filter(author__name='lqz').values('phone') print(ret)
# 查询lqz这个作者的手机号
# 正向
ret=Author.objects.filter(name='lqz').values('authordetail_id__phone') print(ret)
#查询手机号是 1529874130 的作者
ret=Author.objects.filter(authordetail_id__phone='1529874130') print(ret) ret=Author_details.objects.filter(phone='1529874130') print(ret)
文章标题:八、多表模型操作,基于对象的跨表查询,基于双下划线的跨表查询
标题URL:http://cdiso.cn/article/psgeee.html