django 模型层 多表操作 跨表连接

模型层


1.多表操作

0.今日内容

 1 0.今日内容:
 2     模层型
 3         神奇的双下滑查询
 4         多表操作
 5             0.1图书管理系统表创建
 6             0.2.SQL语句 打印(settings 配置修改)
 7             1.一对多字段的增删改查
 8             2.多对多字典的增删改查
 9             ORM跨表查询(*****)
10                 基于对象的跨表查询
11                 基于双下划线的的查询
12 
13 今日知识点:
14         01 昨日内容回顾.mp4
15         02 神奇的双下划线查询.mp4
16         03 图书管理系统表设计.mp4
17         04 外键字段的增删改查.mp4
18         05 基于对象的正反向查询.mp4
19         06 基于双下滑线的正反向查询.mp4
20         07 聚合查询.mp4
21         08 分组查询.mp4
22         09 F与Q查询.mp4
23 
24 
25 
26 明日内容:
27             ORM常见字段
28             ORM事务操作
29             ORM查询优化
0.今日内容:

0.1图书管理表创建

 1 from django.db import models
 2 
 3 # Create your models here.
 4 #
 5 class Book(models.Model):
 6     title = models.CharField(max_length=255)
 7     price = models.DecimalField(max_digits=8, decimal_places=2)
 8     publish_date = models.DateField(auto_now_add=True)
 9 
10     # 库存数
11     kucun = models.IntegerField(null=True)
12     # 卖出数
13     maichu = models.IntegerField(null=True)
14 
15     publish = models.ForeignKey(to='Publish')  # 默认是跟publish的主键字段做的一对多外键关联
16     authors = models.ManyToManyField(to='Author')
17 
18     # 虚拟字段      1.自动创建第三张表    2.帮助orm跨表查询
19 
20     def __str__(self):
21         return self.title
22 
23 # 出版社
24 class Publish(models.Model):
25     name = models.CharField(max_length=32)
26     addr = models.CharField(max_length=32)
27 
28     # email = models.EmailField()  # 就是varchar(254)
29 
30     def __str__(self):
31         return self.name
32 
33 # 作家信息
34 class Author(models.Model):
35     name = models.CharField(max_length=32)
36     age = models.IntegerField()
37     author_detail = models.OneToOneField(to='AuthorDetail')
38 
39     def __str__(self):
40         return self.name
41 
42 
43 class AuthorDetail(models.Model):
44     phone = models.BigIntegerField()
45     addr = models.CharField(max_length=64)
46     """
47     models.py中的模型类__str__方法 必须返回一个字符串形式数据!!!
48 
49     """
50 
51     def __str__(self):
52         return self.addr
0.1图书管理表创建

0.2.settings 增加sql语句查询

 1 LOGGING = {
 2     'version': 1,
 3     'disable_existing_loggers': False,
 4     'handlers': {
 5         'console':{
 6             'level':'DEBUG',
 7             'class':'logging.StreamHandler',
 8         },
 9     },
10     'loggers': {
11         'django.db.backends': {
12             'handlers': ['console'],
13             'propagate': True,
14             'level':'DEBUG',
15         },
16     }
17 }
0.2.settings 增加sql语句查询


1.一对多字段的增删改查

 1 app01/tests.py
 2 
 3 from django.test import TestCase
 4 
 5 # Create your tests here.
 6 import os
 7 
 8 if __name__ == '__main__':
 9     # 注,去 manage.py文件拷贝
10     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day55模板层.settings")
11     import django
12     django.setup()
13     """在下面就可以写针对某一个py文件的测试代码"""
14     from app01 import models
15 
16     # # 1.一对多字段的增删改查
17     #
18     # 1.publish_id 传数字
19     # res = models.Book.objects.create(title='封神演义',price=745,publish_id=1)
20     # print(res)
21     # sql语句
22     # INSERT INTO `app01_book` (`title`, `price`, `publish_date`, `kucun`, `maichu`, `publish_id`) VALUES ('封神演义', '745.00', '2019-09-19', NULL, NULL, 1); args=['封神演义', '745.00', '2019-09-19', None, None, 1]
23     #  res   封神演义
24 
25     #  2.publish直接传出版社对象
26     # 指定出版社对象
27     # publish_obj = models.Publish.objects.filter(pk=2).first()
28     # # 传参
29     # res = models.Book.objects.create(title='一世之尊',price=999.00,publish=publish_obj)
30     # print(res)
31 
32     # sql语句
33     # SELECT `app01_publish`.`id`, `app01_publish`.`name`, `app01_publish`.`addr` FROM `app01_publish` WHERE `app01_publish`.`id` = 2 ORDER BY `app01_publish`.`id` ASC LIMIT 1; args=(2,)
34     # INSERT INTO `app01_book` (`title`, `price`, `publish_date`, `kucun`, `maichu`, `publish_id`) VALUES ('一世之尊', '999.00', '2019-09-19', NULL, NULL, 2); args=['一世之尊', '999.00', '2019-09-19', None, None, 2]
35     # 一世之尊
36 
37     # # 2.改
38     # 1.传数字的
39     # models.Book.objects.filter(pk=1).update(publish_id=3)
40     # 2.传对象的
41     # publish_obj = models.Publish.objects.filter(pk=2).first()
42     # models.Book.objects.filter(pk=1).update(publish=publish_obj)
43 
44     #
45     # res = models.Book.objects.filter(pk=3).first()
46     # print(res.title,res.price)   # 水浒传 777.00
47 
48     #
49     # models.Publish.objects.filter(pk=7).delete()  # 默认都是级联更新 级联删除
1.一对多字段的增删改查


2.多对多增删改查

 1 # # 2.多对多字段的增删改查
 2     #
 3     # 要给主键为1的书籍添加两个作者
 4     # book_obj = models.Book.objects.filter(pk=1).first()
 5     # print(book_obj.authors)  # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
 6     # book_obj.authors.add(3,2)
 7     # book_obj.authors.add(2,4)
 8 
 9     # author_obj = models.Author.objects.filter(pk=1).first()
10     # author_obj1 = models.Author.objects.filter(pk=2).first()
11     # author_obj2 = models.Author.objects.filter(pk=3).first()
12     # book_obj.authors.add(author_obj)
13     # book_obj.authors.add(author_obj1,author_obj2)
14     """
15     add()
16     是给书籍添加作者  括号内既可以传数字也可以传对象
17     并且支持一次性传多个  逗号隔开即可
18     """
19 
20     ## 2.改
21     # 将主键为1的书籍对象 作者修改为2,3
22     # book_obj = models.Book.objects.filter(pk=1).first()
23     # 修改为 作者2
24     # book_obj.authors.set([2,])
25     # # 修改为 作者3
26     # book_obj.authors.set([2,3])
27 
28     # author_obj = models.Author.objects.filter(pk=1).first()
29     # author_obj1 = models.Author.objects.filter(pk=2).first()
30     # author_obj2 = models.Author.objects.filter(pk=3).first()
31     # book_obj.authors.set([author_obj,])
32     # book_obj.authors.set([author_obj, author_obj1, author_obj2])
33     """
34     set()括号内
35         需要传一个可迭代对象
36     可迭代对象中
37         1.可以是多个数字组合
38         2.也可以是多个对象组合
39         ps:但是不要混着用!!!
40     """
41 
42     #
43     # book_obj = models.Book.objects.filter(pk=1).first()
44     # book_obj.authors.remove(3)
45     # book_obj.authors.remove(1,2)
46     # author_obj = models.Author.objects.filter(pk=1).first()
47     # author_obj1 = models.Author.objects.filter(pk=2).first()
48     # author_obj2 = models.Author.objects.filter(pk=3).first()
49     # book_obj.authors.remove(author_obj)
50     # book_obj.authors.remove(author_obj1,author_obj2)
51     # book_obj.authors.remove(author_obj1, 3)
52     """
53     remove()括号内
54         1.既可以传数字
55         2.也可以传对象
56     并且支持传对个(即:数字,对象混合传) 逗号隔开即可
57     """
58 
59     # 将某本书跟作者的关系全部清空
60     # book_obj = models.Book.objects.filter(pk=1).first()
61     # book_obj.authors.clear()  # 清空当前书籍与作者的所有关系
62 
63     """
64     add()   添加 作者关系
65     set()   修改 作者关系
66     remove()    删除指定作者关系
67     上面三个都支持传数字 或者对象 并且可以传多个 但是set需要传可迭代对象
68 
69     clear()   # 全部清空
70     clear括号内不需要传任何参数
71     """
2.多对多字段的增删改查


2.跨表查询


0. 跨表操作 神奇的双下划綫

 1 跨表操作:
 2     1 基于对象的正反向查询.mp4
 3     2 基于双下滑线的正反向查询.mp4
 4     3 聚合查询.mp4
 5     4 分组查询.mp4
 6     5 F与Q查询.mp4
 7 
 8 """
 9     """子查询"""
10     """
11     基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)"""
12     """
13     强调:在书写orm语句的时候 跟写sql语句一样
14     不要尝试着 一次性写完  应该做到写一点看一点再一点
15 """
0. 跨表操作 神奇的双下划綫


1.正向与反向的概念

  1 正向与反向的概念:
  2 
  3     1. 一对一
  4     # 正向:按字段
  5     author---关联字段在author表里--->authordetail        按字段
  6     # 反向:按表名小写
  7     authordetail---关联字段在author表里--->author        按表名小写
  8 
  9     2.一对多
 10     # 正向:按字段
 11     book---关联字段在book表里--->publish        按字段
 12     # 反向:按表名小写
 13     publish---关联字段在book表里--->book        按表名小写_set.all() 因为一个出版社对应着多个图书
 14 
 15     3. 多对多
 16     # 正向:按字段
 17     book---关联字段在book表里--->author        按字段
 18     # 反向:按表名小写
 19     author---关联字段在book表里--->book        按表名小写_set.all() 因为一个作者对应着多个图书
 20 
 21     结论:
 22         正向查询按外键字段
 23         反向查询按表名小写
 24 
 25 
 26 2. 基于对象的正反向查询
 27 
 28     """子查询"""
 29     # 1.查询书籍id是1 的出版社名称
 30     # book_obj = models.Book.objects.filter(pk=1).first()
 31     # print(book_obj.publish.name)
 32     # print(book_obj.publish.addr)
 33 
 34     # 2.查询书籍id是2 的作者姓名
 35     # book_obj = models.Book.objects.filter(pk=2).first()
 36     # print(book_obj.authors)  # app01.Author.None
 37     # print(book_obj.authors.all())
 38     # res = book_obj.authors.all()
 39     # for r in res:
 40     #     print(r.name)
 41 
 42     # 3.查询作者是jason的家庭住址
 43     # author_obj = models.Author.objects.filter(name='jason').first()
 44     # print(author_obj.author_detail.addr)
 45 
 46     # 4.查询出版社是东方出版社出版的书籍
 47     # publish_obj = models.Publish.objects.filter(name='东方出版社').first()
 48     # # print(publish_obj.book_set)  # app01.Book.None
 49     # print(publish_obj.book_set.all())
 50 
 51     # 5.查询作者是jason的写过的所有的书籍
 52     # author_obj = models.Author.objects.filter(name='jzd').first()
 53     # print(author_obj.book_set)  # app01.Book.None
 54     # print(author_obj.book_set.all())   # <QuerySet [<Book: 水浒传>]>
 55 
 56     # 6.查询电话号码是130的作者姓名
 57     # author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first()
 58     # print(author_detail_obj.author.name)
 59     # print(author_detail_obj.author.age)
 60     """
 61     当你反向查询的结果是多个的时候 就需要加_set ,否则会报错
 62     其他正向查询 直接表明小写即可
 63     """
 64 
 65     # 7.查询书籍id为1 的作者的电话号码
 66     # book_obj = models.Book.objects.filter(pk=1).first()
 67     # author_list = book_obj.authors.all()
 68     # for author_obj in author_list:
 69     #     print(author_obj.author_detail.phone)
 70 
 71 
 72 3. 基于双下滑线的正反向查询
 73 
 74 """基于双下划綫的跨表查询(连表操作)
 75             left join
 76             inner join
 77             right join
 78             union
 79         """
 80     # 正向
 81     # 1.查询llx作者的手机号
 82     # 正向 按 外键字段
 83     # res = models.Author.objects.filter(name='jzd').values('author_detail__phone')  # <QuerySet [{'author_detail__phone': 147}]>
 84     # # res = models.Author.objects.filter(name='llx').values('author_detail__phone','author_detail__addr')
 85     # print(res)
 86 
 87     # 反向按表名
 88     # res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
 89     # print(res1)
 90 
 91     # 查询jason这个作者的年龄和手机号
 92     # 正向
 93     # res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
 94     # print(res)
 95     # 反向
 96     # res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
 97     # print(res1)
 98 
 99     # 查询手机号是130的作者年龄
100     # 正向
101     # res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
102     # print(res)
103     # # 反向
104     # res1 = models.Author.objects.filter(author_detail__phone=130).values('age')
105     # print(res1)
106 
107     # 查询书籍id是1 的作者的电话号码
108     # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
109     # res1 = models.Book.objects.filter(pk=1).values('外键字段1__外键字段2__外键字段3__普通字段')
110     # print(res)
111     """只要表里面有外键字段 你就可以无限制跨多张表"""
112 
113     # 1.查询出版社为北方出版社的所有图书的名字和价格
114     # res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price')
115     # print(res)
116 
117     # 2.查询北方出版社出版的价格大于19的书
118     # res = models.Book.objects.filter(price__gt=19,publish__name='北方出版社').values('title','publish__name')
119     # print(res)
1.正向与反向的概念


2.聚合函数

 1 # 聚合查询(关键字 aggregate)
 2     """
 3     # 1.调用内置的聚合函数
 4     # 2.聚合函数只有在进行了分组的情况下 才能 使用
 5     ps:未设置视为默认 以id分组
 6     # from django.db.models import Max,Min,Count,Avg,Sum
 7     """
 8     from django.db.models import Max,Min,Count,Avg,Sum
 9     # 1.统计所有书的总价格
10     # res = models.Book.objects.aggregate(Sum('price'))  # SELECT SUM(`app01_book`.`price`) AS `price__sum` FROM `app01_book`; args=()
11     # print(res)      # {'price__sum': Decimal('5264.00')}
12     # res1 = models.Book.objects.aggregate(Avg('price'))
13     # res2 = models.Book.objects.aggregate(Count('price'))
14     # res3 = models.Book.objects.aggregate(Max('price'))
15     # res4 = models.Book.objects.aggregate(Min('price'))
16 
17     # res5 = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price'))
18     # print(res5)
19     # print(res)
20     # print(res1)
21     # print(res2)
2.聚合函数


3.分组查询

 1 # 分组查询 (关键字 annotate)
 2     """
 3     from django.db.models import Max, Min, Count, Avg, Sum
 4     """
 5     from django.db.models import Max, Min, Count, Avg, Sum
 6     # 统计每一本书的作者个数
 7     # res = models.Book.objects.annotate(author_num = Count('author')).values('author_num')
 8     """
 9     django.core.exceptions.FieldError: Cannot resolve keyword 'author' into field. Choices are: authors, id, kucun, maichu, price, publish, publish_date, publish_id, title
10     根据提示:选择 anthors
11     """
12     # print(res)
13     res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num','title')
14     """
15     SQL语句:
16     SELECT `app01_book`.`title`, COUNT(`app01_book_authors`.`author_id`) AS `author_num` FROM `app01_book` LEFT OUTER JOIN `app01_book_authors` ON (`app01_book`.`id` = `app01_book_authors`.`book_id`) GROUP BY `app01_book`.`id` ORDER BY NULL LIMIT 21; args=()
17 
18     """
19     print(res)
20     """
21     <QuerySet [{'title': '三国演义', 'author_num': 0}, {'title': '红楼梦', 'author_num': 1}, {'title': '水浒传', 'author_num': 1}, {'title': '西游记', 'author_num': 1}, {'title': '封神演义', 'author_num': 0}, {'title': '封神演义', 'author_num': 0}, {'title': '一世之尊', 'author_num': 0}]>
22 
23     """
24 
25     # 统计出每个出版社卖的最便宜的书的价格
26     # res = models.Publish.objects.annotate(mmp = Min('book__price')).values('name','mmp')
27     # print(res)
28 
29     # 统计不止一个作者的图书
30     # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
31     # print(res)
32 
33     """
34     只要是queryset对象 就可以无限制的调用queryset对象的方法!!!
35     最最常用的就是对一个已经filter过滤完的数据 再进行更细化的筛选
36 
37     """
38 
39     # 查询各个作者出的书的总价格
40     # res = models.Author.objects.annotate(sp=Sum('book__price')).values('name','sp')
41     # print(res)
3.分组查询


4.F 与 Q 查询

 1 """F | Q查询"""
 2     """F查询"""
 3     # F查询的本质就是从数据库中获取某个字段的值
 4     # 查询库存数大于卖出数的书籍
 5     """之前查询等号后面的条件都是我们认为输入的
 6         现在变成了需要从数据库中获取数据放在等号后面 ,引出 F查询方法
 7     """
 8     from django.db.models import F
 9     # res = models.Book.objects.filter(maichu__gt=F('kucun'))  # <QuerySet [<Book: 三国演义>]>
10     """
11     maichu__gt=F('kucun')
12     maichu__gt 表示大于 获取前边变量的值
13     F('kucun')   # 去表中 遍历取值
14     """
15     # res = models.Book.objects.filter(kucun__gt=F('maichu'))
16     # print(res)
17 
18     """1.运算 """
19     # models.Book.objects.update(maichu=F('maichu')/1000)
20     # 将书籍库存数全部增加1000
21     # models.Book.objects.update(kucun=F('kucun')+1000)
22 
23     """2.拓展"""
24     # 把所有书名后面加上'新款'
25 
26     from django.db.models.functions import Concat
27     from django.db.models import Value
28     #
29     ret3 = models.Book.objects.update(title=Concat(F('title'), Value('')))
30     # models.Book.objects.update(title = F('title')+'新款')  # 不能这么写
31 
32     # Q查询
33     from django.db.models import Q
34 
35     # 查询书籍名称是三国演义或者价格是444.44
36     # res = models.Book.objects.filter(title='三国演义',price=444.44)  # filter只支持and关系
37     res1 = models.Book.objects.filter(Q(title='三国演义新款'),Q(price=999))  # 如果用逗号 那么还是and关系
38     # res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
39     # res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))
40     # print(res2)
41 
42     # Q高级用法
43     # q = Q()
44     # q.connector = 'or'  # 修改查询条件的关系   默认是and
45     # q.children.append(('title__contains', '三国演义'))  # 往列表中添加筛选条件
46     # q.children.append(('price__gt', 444))  # 往列表中添加筛选条件
47     # res = models.Book.objects.filter(q)  # filter支持你直接传q对象  但是默认还是and关系
48     print(res1)
4.F 与 Q 查询

猜你喜欢

转载自www.cnblogs.com/llx--20190411/p/11552769.html
今日推荐