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查詢優化
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
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 }
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.多對多字段的增刪改查 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 """
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 """
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 # 聚合查詢(關鍵字 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)
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)
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)