django 模型層 多表操做 跨錶鏈接 # 55

模型層


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 查詢
相關文章
相關標籤/搜索