目录
数据准备
moduls.py
# 构建表结构 from django.db import models # 表app01_publish class Publish(models.Model): name = models.CharField(max_length=20) addr = models.CharField(max_length=20) # 表app01_author_detail class Author_Detail(models.Model): tel = models.CharField(max_length=20) # 表app01_author class Author(models.Model): name = models.CharField(max_length=20) age = models.IntegerField() # 表app01_author一对一表app01_authordetail detail = models.OneToOneField(to=\'Author_Detail\',to_field=\'id\',unique=True,on_delete=models.CASCADE) # 表app01_book class Book(models.Model): title = models.CharField(max_length=20) price = models.DecimalField(max_digits=8, decimal_places=2) pub_date = models.DateField(auto_now_add=True) # 表app01_book多对一表app01_publish,参数to指定模型名,参数to_field指定要关联的那个字段 publish = models.ForeignKey(to=\'Publish\',to_field=\'id\',on_delete=models.CASCADE) # 我们自己写sql时,针对书籍表与作者表的多对关系,需要自己创建新表,而基于django的orm,下面这一行代码可以帮我们自动创建那张关系表 authors=models.ManyToManyField(to=\'Author\') # 变量名为authors,则新表名为app01_book_authors,若变量名为xxx,则新表名为app01_book_xxx
tests.py
# 添加数据 import os if __name__ == \"__main__\": os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"book_sys.settings\") import django django.setup() from app01.models import * # 1、先添加没有外键字段的 author_detail表 pubulish表 Author_Detail.objects.create(tel=\'123456789\') Author_Detail.objects.create(tel=\'987654321\') Author_Detail.objects.create(tel=\'000000000\') Publish.objects.create(name=\'北方出版社\',addr=\'北京\') Publish.objects.create(name=\'南方出版社\',addr=\'南京\') Publish.objects.create(name=\'东方出版社\',addr=\'上海\') Publish.objects.create(name=\'西方出版社\',addr=\'西安\') # 2、添加 author表 book表 Author.objects.create(name=\'frank\',age=31 ,detail_id=1) Author.objects.create(name=\'lili\',age=29 ,detail_id=2) Author.objects.create(name=\'tank\',age=42 ,detail_id=3) Book.objects.create(title=\'三国演义\',price=200 ,publish_id=1) Book.objects.create(title=\'三国志\',price=198.5 ,publish_id=2) Book.objects.create(title=\'红楼梦\',price=255.43 ,publish_id=2) Book.objects.create(title=\'西游记\',price=300.5 ,publish_id=3) Book.objects.create(title=\'西厢记\',price=213.4 ,publish_id=4) Book.objects.create(title=\'水浒传\',price=199 ,publish_id=1) # 3、最后操作 author_book表,由于使用的是 ManyToMany 字段自动生成的,所以要基于外键所在的表进行操作 book_obj1=Book.objects.filter(pk=1).first() book_obj1.authors.add(1,2) book_obj2 = Book.objects.filter(pk=2).first() book_obj2.authors.add(1) book_obj3 = Book.objects.filter(pk=3).first() author_obj1 = Author.objects.filter(pk=1).first() author_obj2 = Author.objects.filter(pk=2).first() book_obj3.authors.add(author_obj1,author_obj2) book_obj4 = Book.objects.filter(pk=4).first() book_obj4.authors.add(3,2) book_obj5 = Book.objects.filter(pk=5).first() book_obj5.authors.add(3) book_obj6 = Book.objects.filter(pk=6).first() book_obj6.authors.add(1,3)
正向查询与反向查询
一出版社和书籍为例, 书记表含有出版社表的外键字段
正向查询>>> 书籍查询出版社
反向查询>>> 出版社查询书籍
总结: 当前查询对象是否含有外键字段, 有就是正向查询, 没有就是反向查询
正向查询按照字段查询, 反向查询按照表名查询
基于对象的跨表查询
相当于MySQL中的子查询: 将一张表的查询结果用括号括起来, 当作另一条SQL语句的条件 .
正向查询
一对多
查询书籍主键为5 的出版社名称
1. 查主键为5的书籍对象
2. 根据书籍对象的外键字段 publish 获取到出版社对象
3. 由出版社对象获取到名称
book_obj = Book.objects.filter(pk=5).first() res = book_obj.publish print(res) # Publish object print(res.name) # 西方出版社
多对多
查询书籍主键为3的作者姓名
1. 查询书籍主键为3的书籍对象
2. 外键字段在书籍表中, 同样是正向查询,那么只需要按照字段autjors查询即可
3. 获取作者对象的姓名
book_obj = Book.objects.filter(pk=3).first() res = book_obj.authors print(res) # app01.Author.None
注意: 由于字段authors 是多对多的外键字段, 此时拿到的对象还需要进一步的操作
book_obj = Book.objects.filter(pk=3).first() res = book_obj.authors res1 = book_obj.authors.all() print(res1) # <QuerySet [<Author: Author object>, <Author: Author object>]>
然后再for循环各自的姓名即可
一对一
查询作者lili的号码
1.查询作者对象
2,外键字段再作者表中, 同样是正向查询,那么只需要按照字典detail查询即可
3. 获取详情对象的tel
author_obj = Author.objects.filter(name=\'lili\').first() res = author_obj.detail print(res) print(res.tel)
反向查询 一对多
查询东方出版社出版的书籍
1. 先获取东方出版社的对象
2. 出版社没有外键字段, 去查书籍是反向查询
3. 表名小写_set.all()
4. 获取书籍名称
publish_obj=Publish.objects.filter(name=\'东方出版社\').first() print(publish_obj) # Publish object res = publish_obj.book_set print(res) # app01.Book.None res1 = res.all() print(res1) # <QuerySet [<Book: Book object>]> for obj in res1: print(obj.title)
多对多
查询作者lili写过的书籍
1.获取作者对象
2. 作者表中没有书籍表的外键, 所以是反向查询
3. .book_set.all()获取书籍对象
4. 再获取书籍对象的名称
author_obj = Author.objects.filter(name=\'lili\').first() res = author_obj.book_set print(res) # app01.Book.None res1 = res.all() print(res1) # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]> for obj in res1: print(obj.title, end=\'\') # 三国演义,红楼梦,西游记,
一对一
查询号码为0000000的作者
1. 查询作者对象详情
2.外键字段在作者表中, 同样是证词昂查询, 那么只需要按照字段detail 查询即可
3. 获取详情对象的tel
detail_obj = Author_Detail.objects.filter(tel=\'000000000\').first() print(detail_obj) # Author_Detail object res = detail_obj.author print(res) # Author object print(res.name) # tank
方法总结
正向查询
一对一, 一对多的方法是一样的, 按照字段查询就能够直接找到对象 — author_obj.detail
一对多 , 按照字段查询后会返回一个.None的对象, 需要在字段后面加上.all()>>> book_obj.authors.all()
反向查询
一对多,多对多的方法是一样的, 按照表名小写, 在跟上_set.all()>>>author_obj.book_set.all()
一对一, 则直接按照表明小写, 能够直接拿到>> > detail_obj.author
当查询到的结果中最后以.None结尾, 都需要在原来的查询方法后面在跟上.all()才能获得想要的结果
基于双下线的跨表查询
相当于MySQL中的连表查询: 将两张表或者对账表连成一张表进行查询
正向查询
正向查询, 按照关联字段+双下线>>> .values('关联字段__被关联表中的字段'), 返回的是一个QuerySet对象
一对一
查询作者frank的手机号
res = Author.objects.filter(name=\'frank\').values(\'detail__tel\') print(res) # <QuerySet [{\'detail__tel\': \'123456789\'}]> print(res.first()) # {\'detail__tel\': \'123456789\'}
一对多
查询三国演义的出版社名字
res = Book.objects.filter(title=\'三国演义\').values(\'publish__name\') print(res) print(res.first()) # <QuerySet [{\'publish__name\': \'北方出版社\'}]> # {\'publish__name\': \'北方出版社\'}
多对多
查询三国演义的所有作者
res = Book.objects.filter(title=\'三国演义\').values(\'authors__name\') print(res) # <QuerySet [{\'authors__name\': \'frank\'}, {\'authors__name\': \'lili\'}]>
反向查询
按模型名(小写)+双下线>>> .values('表名小写__被关联表中的字段'), 返回的是一个QuerySet对象.
一对一
查询手机号为'123456789'的作者名
res = Author_Detail.objects.filter(tel=\'123456789\').values(\'author__name\') print(res) # <QuerySet [{\'author__name\': \'frank\'}]>
一对多
查询北方出版社出版的所有书籍名字
res = Publish.objects.filter(name=\'北方出版社\').values(\'book__title\') print(res) # <QuerySet [{\'book__title\': \'三国演义\'}, {\'book__title\': \'水浒传\'}]>
多对多
查询lili出版的所有书籍
res = Author.objects.filter(name=\'lili\').values(\'book__title\') print(res) # <QuerySet [{\'book__title\': \'三国演义\'}, {\'book__title\': \'红楼梦\'}, {\'book__title\': \'西游记\'}]>
方法总结:
正向查询,按关联字段: .values('关联字段__被关联表中的字段'), 返回的是一个QuerySet对象
按模型名(小写)+双下线: .values('表名小写__被关联表中的字段'), 返回的是一个QuerySet对象, 对象中保存的是字典类型的数据
双下高阶正反向查询
使用filter()的双下线查询
首先需要考虑的是正向查询还是反向查询, 确定括号内使用的方法, 但是括号外面不是使用values,而是使用filter!!!
注意: 使用filter方法字段是不能加引号的, values需要加引号
查询书籍主键为反向, 使用.filter('表名小写__被关联表中的字段')
res = Publish.objects.filter(book__pk= 4) print(res) # <QuerySet [<Publish: Publish object>]> res = Publish.objects.filter(book__title= \'西游记\') print(res) # 结果相同
连续跨多张表查询
套路与上面的案例都是一样的, 可以练习n个双下划线, 只需要在每次双下线的时候, 确定是每个双下线后面是正向查询还是反向查询即可
# 需求1:查询北京出版社出版过的所有书籍的名字以及作者的姓名、手机号 # 方式一:基表为Publish res=Publish.objects.filter(name=\'北方出版社\').values_list(\'book__title\',\'book__authors__name\',\'book__authors__author_detail__tel\') # 方式二:基表为Book res=Book.objects.filter(publish__name=\'北方出版社\').values_list(\'title\',\'authors__name\',\'authors__author_detail__tel\') # 循环打印结果均为 for obj in res: print(obj) # 需求2:查询手机号以186开头的作者出版过的所有书籍名称以及出版社名称 # 方式一:基表为AuthorDetail res=AuthorDetail.objects.filter(tel__startswith=\'186\').values_list(\'author__book__title\',\'author__book__publish__name\') # 方式二:基表为Book res=Book.objects.filter(authors__author_detail__tel__startswith=\'186\').values_list(\'title\',\'publish__name\') # 方式三:基表为Publish res=Publish.objects.filter(book__authors__author_detail__tel__startswith=\'186\').values_list(\'book__title\',\'name\') # 循环打印结果均为 for obj in res: print(obj)
暂无评论内容