單獨的py文件測試ORM操做須要配置的參數python
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings") import django django.setup() from app01 import models # 這一句話必須在這下面導入
""" 查看orm內部sql語句的方法有哪些 1.若是是queryset對象 那麼能夠點query直接查看該queryset的內部sql語句 2.在django項目的配置文件中 配置一下參數便可實現全部的orm在查詢的時候自動打印對應的sql語句 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } } """
當一張表已經建立出來以後 後續還想添加字段,能夠有兩種方式mysql
刪除字段 直接在models.py中註釋該字段 而後從新執行兩條命令便可
注意: 執行完以後 表中該字段所對應的全部的數據所有刪除
而且通常狀況下 基本是不會用到真正意義上的刪除sql
查:數據庫
增:django
刪:
models.User.objects.filter(條件).delete()併發
改:
models.User.objects.filter(條件).update()app
__gt 大於 __lt 小於 __gte 大於等於 __lte 小於等於 __in 在某範圍內(包含兩頭) __range 是否在設定的幾個選擇中
案例:測試
"""神奇的雙下滑查詢""" # 查詢價格大於200的書籍 # res = models.Book.objects.filter(price__gt=200) # print(res) # 查詢價格小於200的書籍 # res = models.Book.objects.filter(price__lt=200) # print(res) # 查詢價格大於等於200.22的書籍 # res = models.Book.objects.filter(price__gte=200.22) # print(res) # 查詢價格小於等於200.22的書籍 # res = models.Book.objects.filter(price__lte=200.22) # print(res) # 查詢價格要麼是200,要麼是300,要麼是666.66 # res = models.Book.objects.filter(price__in=[200,300,666.66]) # print(res) # 查詢價格在200到800之間的 # res = models.Book.objects.filter(price__range=(200,800)) # 兩邊都包含 # print(res) # 查詢書籍名字中包含p的 """原生sql語句 模糊匹配 like % _ """ # res = models.Book.objects.filter(title__contains='p') # 僅僅只能拿小寫p # res = models.Book.objects.filter(title__icontains='p') # 忽略大小寫 # print(res) # 查詢書籍是以三開頭的 # res = models.Book.objects.filter(title__startswith='三') # res1 = models.Book.objects.filter(title__endswith='p') # print(res) # print(res1) # 查詢出版日期是2017的年(******) res = models.Book.objects.filter(create_time__year='2017') print(res)
我的小總結: 熟練利用 __ ,熟練使用 __ 的相關方法便可fetch
add() # 添加
set() # 修改
remove() # 不能接收可迭代對象
clear() # 清空 不用傳參
# 一對多的字段的增刪改查 # 增 # publish_id傳數字 # models.Book.objects.create(title='三國演義',price=189.99,publish_id=1) # publish直接傳出版社對象 # publish_obj = models.Publish.objects.filter(pk=2).first() # models.Book.objects.create(title='紅樓夢',price=999.99,publish=publish_obj) # 改 # 傳數字的 # models.Book.objects.filter(pk=1).update(publish_id=3) # 傳對象的 # publish_obj = models.Publish.objects.filter(pk=2).first() # models.Book.objects.filter(pk=1).update(publish=publish_obj) # 查 # 刪 # models.Publish.objects.filter(pk=2).delete() # 默認都是級聯更新 級聯刪除
我的小總結:優化
正反向跨表就完事了,利用好雙下滑線,上面例子沒用,有些注意點就是 關於創建關聯時候單表 __id對應的自動建表時候出來的字段, 給它賦對應數字id能夠創建關係,要麼就是 外鍵= 對象方式
# 多對多字段的增刪改查 # 增 # 要給主鍵爲1的書籍添加兩個做者 # book_obj = models.Book.objects.filter(pk=1).first() # print(book_obj.authors) # 對象點擊多對多虛擬字段 會直接跨到多對多的第三張表 # book_obj.authors.add(1) # book_obj.authors.add(2,3) # author_obj = models.Author.objects.filter(pk=1).first() # author_obj1 = models.Author.objects.filter(pk=2).first() # author_obj2 = models.Author.objects.filter(pk=3).first() # book_obj.authors.add(author_obj) # book_obj.authors.add(author_obj1,author_obj2) """ add() 是給書籍添加做者 括號內既能夠傳數字也能夠傳對象 而且支持一次性傳多個 逗號隔開便可 """ # 改 # 將主鍵爲1的書籍對象 做者修改成2,3 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.set([2,]) # book_obj.authors.set([2,3]) # author_obj = models.Author.objects.filter(pk=1).first() # author_obj1 = models.Author.objects.filter(pk=2).first() # author_obj2 = models.Author.objects.filter(pk=3).first() # book_obj.authors.set([author_obj,]) # book_obj.authors.set([author_obj, author_obj1, author_obj2]) """ set()括號內 須要傳一個可迭代對象 可迭代對象中 能夠是多個數字組合 也能夠是多個對象組合 可是不要混着用!!! """ # 刪 # book_obj = models.Book.objects.filter(pk=1).first() # # book_obj.authors.remove(3) # book_obj.authors.remove(1,2) # author_obj = models.Author.objects.filter(pk=1).first() # author_obj1 = models.Author.objects.filter(pk=2).first() # author_obj2 = models.Author.objects.filter(pk=3).first() # book_obj.authors.remove(author_obj) # book_obj.authors.remove(author_obj1,author_obj2) """ remove()括號內既能夠傳數字 也能夠傳對象 而且支持傳對個 逗號隔開便可 """ # 將某本書跟做者的關係所有清空 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.clear() # 清空當前書籍與做者的全部關係 """ add() set() remove() 上面三個都支持傳數字 或者對象 而且能夠傳多個 可是set須要傳可迭代對象 clear() clear括號內不須要傳任何參數 """
我的小總結:
利用好外鍵跨表,正反向跨表就完事了,利用好雙下滑線,上面例子沒用,有些注意點 ==>
add,set對象和id都不能混着用
能夠經過id或對象添加關聯,支持 逗號(,) 隔開傳多個
set()括號內 須要傳一個可迭代對象 ,可迭代對象中 能夠是多個數字組合
remove()括號內既能夠傳數字 也能夠傳對象 ,而且支持傳多個 逗號隔開便可
clear括號內不須要傳任何參數
換句話說 只有set須要可迭代對象
""" 正向與反向的概念 # 一對一 # 正向:author---關聯字段在author表裏--->authordetail 按字段 # 反向:authordetail---關聯字段在author表裏--->author 按表名小寫 # 一對多 # 正向:book---關聯字段在book表裏--->publish 按字段 # 反向:publish---關聯字段在book表裏--->book 按表名小寫_set.all() 由於一個出版社對應着多個圖書 # 多對多 # 正向:book---關聯字段在book表裏--->author 按字段 # 反向:author---關聯字段在book表裏--->book 按表名小寫_set.all() 由於一個做者對應着多個圖書 正向查詢按外鍵字段 反向查詢按表名小寫 """ """基於對象的跨表查詢(子查詢:將一張表的查詢結果當作另一個查詢語句的條件)""" """ 強調:在書寫orm語句的時候 跟寫sql語句同樣 不要嘗試着 一次性寫完 應該作到寫一點看一點再一點 """ # 1.查詢書籍id是1 的出版社名稱 # book_obj = models.Book.objects.filter(pk=1).first() # print(book_obj.publish.name) # print(book_obj.publish.addr) # 2.查詢書籍id是2 的做者姓名 # book_obj = models.Book.objects.filter(pk=2).first() # print(book_obj.authors) # app01.Author.None # print(book_obj.authors.all()) # res = book_obj.authors.all() # for r in res: # print(r.name) # 3.查詢做者是jason的家庭住址 # author_obj = models.Author.objects.filter(name='jason').first() # print(author_obj.author_detail.addr) # 4.查詢出版社是東方出版社出版的書籍 # publish_obj = models.Publish.objects.filter(name='東方出版社').first() # # print(publish_obj.book_set) # app01.Book.None # print(publish_obj.book_set.all()) # 5.查詢做者是jason的寫過的全部的書籍 # author_obj = models.Author.objects.filter(name='jason').first() # print(author_obj.book_set) # app01.Book.None # print(author_obj.book_set.all()) # 6.查詢電話號碼是130的做者姓名 # author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first() # print(author_detail_obj.author.name) # print(author_detail_obj.author.age) """ 當你反向查詢的結果是多個的時候 就須要加_set 不然直接代表小寫便可 """ # 7.查詢書籍id爲1 的做者的電話號碼 # book_obj = models.Book.objects.filter(pk=1).first() # author_list = book_obj.authors.all() # for author_obj in author_list: # print(author_obj.author_detail.phone) """基於雙下劃綫的跨表查詢(連表操做) left join inner join right join union """ # 正向 # 1.查詢jason做者的手機號 # res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr') # print(res) # res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone') # print(res1) # 查詢jason這個做者的年齡和手機號 # 正向 # res = models.Author.objects.filter(name='jason').values('age','author_detail__phone') # print(res) # 反向 # res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age') # print(res1) # 查詢手機號是130的做者年齡 # 正向 # res = models.AuthorDetail.objects.filter(phone=130).values('author__age') # print(res) # # 反向 # res1 = models.Author.objects.filter(author_detail__phone=130).values('age') # print(res1) # 查詢書籍id是1 的做者的電話號碼 # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone') # res1 = models.Book.objects.filter(pk=1).values('外鍵字段1__外鍵字段2__外鍵字段3__普通字段') # print(res) """只要表裏面有外鍵字段 你就能夠無限制跨多張表""" # 1.查詢出版社爲北方出版社的全部圖書的名字和價格 # res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price') # print(res) # 2.查詢北方出版社出版的價格大於19的書 # res = models.Book.objects.filter(price__gt=19,publish__name='北方出版社').values('title','publish__name') # print(res)
from django.db.models import Max, Min, Count, Avg, Sum
是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。
# 1.統計全部書的總價格 # from django.db.models import Max,Min,Count,Avg,Sum # # # res = models.Book.objects.aggregate(Sum('price')) # res1 = models.Book.objects.aggregate(Avg('price')) # res2 = models.Book.objects.aggregate(Count('price')) # res3 = models.Book.objects.aggregate(Max('price')) # res4 = models.Book.objects.aggregate(Min('price')) # res5 = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price')) # print(res5) # print(res) # print(res1) # print(res2)
我的口水總結:
思考方式==> aggregate以後 對應的字符串就是搜索條件,已經獲取相關的對應條件全部對象的對應條件數值後,對它進行 其餘的方法,好比 (Count,Max等等) 這時候能夠 = 方式賦值, 當前指向 改位置的變量 , .values() 裏面能夠作爲字符串方式呈現, 做爲搜索結果的一個 key
運用場景聯想==>
針對全部時候考慮
聚合, 把分散的結合彙總起來統計 , 好比 書不少, 價格檔次不一樣, 這時候aggregate 根據不一樣的書得到對應全部的檔次(這邊是全考慮,不考慮任何分組), 而後能夠針對這全部檔次的數據能夠進一步進行方法操做
from django.db.models import Max, Min, Count, Avg, Sum
# 統計每一本書的做者個數 from django.db.models import Max, Min, Count, Avg, Sum # res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num','title') # print(res) # 統計出每一個出版社賣的最便宜的書的價格 # res = models.Publish.objects.annotate(mmp = Min('book__price')).values('name','mmp') # print(res) # 統計不止一個做者的圖書 # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1) # print(res) """ 只要是queryset對象 就能夠無限制的調用queryset對象的方法!!! 最最經常使用的就是對一個已經filter過濾完的數據 再進行更細化的篩選 """ # 查詢各個做者出的書的總價格 # res = models.Author.objects.annotate(sp=Sum('book__price')).values('name','sp') # print(res) #F查詢的本質就是從數據庫中獲取某個字段的值 # 查詢庫存數大於賣出數的書籍 """以前查詢等號後面的條件都是咱們認爲輸入的 如今變成了須要從數據庫中獲取數據放在等號後面 """
我的口水總結:
思考方式==> annotate以後 對應的字符串就是搜索條件,而後搜索條件獲取對應條件的對象而後對他們進行分組,以後能夠對它們進行 其餘的方法,好比 (Count,Max等等) 這時候能夠 = 方式賦值, 當前指向 該位置的變量 , .values() 裏面能夠作爲字符串方式呈現, 做爲搜索結果的一個 key
運用場景聯想==>
針對各個狀況考慮
分組, 把分散的結合彙總起來 , 好比 書不少, 價格檔次不一樣, 這時候annotate根據不一樣的價格分紅對應的檔次, 每一個檔次對應多個對象, 而後在每一個分組對對應的數據能夠進一步進行操做, 彙總
當搜索條件後面的參數不爲固定值時候想到F或Q查詢
F 能夠幫咱們取到表中某個字段對應的值來看成個人篩選條件
from django.db.models import F
經典案例:
從數據庫中獲取字段對應的數據
列子如: 庫存數大於賣出數
# res = models.Book.objects.filter(kucun__gt=F('maichu')) # print(res) # 將書籍庫存數所有增長1000 # models.Book.objects.update(kucun=F('kucun')+1000) # 把全部書名後面加上'新款' # from django.db.models.functions import Concat # from django.db.models import Value # # ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款'))) # models.Book.objects.update(title = F('title')+'新款') # 不能這麼寫
我的總結:
當搜索條件後面的參數不爲固定值時候想到F,須要字符串拼接時候,用 Concat, Value, 不過須要導入,直接弄 會出問題,全部字段都爲數據單一
Q 實現取反和或
filter() 等方法中逗號隔開的條件是與的關係。 若是你須要執行更復雜的查詢(例如OR語句),你可使用Q對象。
咱們能夠組合& 和| 操做符以及使用括號進行分組來編寫任意複雜的Q 對象。
同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢。
from django.db.models import Q
經典案例:
# 查詢書籍名稱是三國演義或者價格是444.44 # res = models.Book.objects.filter(title='三國演義',price=444.44) # filter只支持and關係 # res1 = models.Book.objects.filter(Q(title='三國演義'),Q(price=444)) # 若是用逗號 那麼仍是and關係 # res2 = models.Book.objects.filter(Q(title='三國演義')|Q(price=444)) # res3 = models.Book.objects.filter(~Q(title='三國演義')|Q(price=444)) # print(res2) # Q高級用法 q = Q() q.connector = 'or' # 修改查詢條件的關係 默認是and q.children.append(('title__contains','三國演義')) # 往列表中添加篩選條件 q.children.append(('price__gt',444)) # 往列表中添加篩選條件 res = models.Book.objects.filter(q) # filter支持你直接傳q對象 可是默認仍是and關係 print(res)
我的口水總結:
或的時候和取反時候考慮, 對應 ~ , |
能夠用Q() 建立對象方法實現對象q q.children爲一個列表,給當前列表添加2參數的元組,做爲對應的搜索條件, 默認爲 and 關係 , 設置 q的 connector = "or" 就可使之稱爲 或關係
ACID 原子性 都爲最小的不可分割的單位,要麼成功要麼失敗 一致性 從一個一致性狀態到另外一個一致性狀態 隔離性 各個數據操做之間是隔離的, 併發操做並不會影響到其餘的數據的操做 持久性 當提交以後數據的狀態就永久肯定恆定,不會由於回退或取消而發送變化
with transaction.atomic():
在裏面進行相關操做,本質就是一個鎖
from django.db import transaction # 哈哈哈, 也是從 django.db導入哩 with transaction.atomic(): """數據庫操做 在該代碼塊中書寫的操做 同屬於一個事務 """ models.Book.objects.create() models.Publish.objects.create() # 添加書籍和出版社 就是同一個事務 要麼一塊兒成功要麼一塊兒失敗 print('出了 代碼塊 事務就結束')
跟數據相關, ORM操做的相關方法, 通常都是從 from django.db import 導入
orm內全部的語句操做都是 惰性查詢:
只會在你真正須要數據的時候纔會走數據庫,若是你單單隻寫orm語句時不會走數據庫的
這樣設計的好處 在於 減輕數據庫的壓力
案例:
# res = models.Book.objects.all() # print(res) # res = models.Book.objects.values('title') # # print(res) # for r in res: # print(r.title) # res = models.Book.objects.only('title') # # print(res) # for r in res: # # print(r.title) # 只走一次數據庫查詢 # print(r.price) # 當你點擊一個不是only括號內指定的字段的時候 不會報錯 而是會頻繁的走數據庫查詢 # res1 = models.Book.objects.defer('title') # defer與only是相反的 # for r in res1: # defer會將不是括號內的全部的字段信息 所有查詢出來封裝對象中 # # 一旦你點擊了括號內的字段 那麼會頻繁的走數據庫查詢 # print(r.price)
defer 與 only 是 相反的
# select_related幫你直接連表操做 查詢數據 括號內只能放外鍵字段 # res = models.Book.objects.all().select_related('publish') # for r in res: # print(r.publish.name) # res = models.Book.objects.all().select_related('publish__xxx__yyy__ttt') # print(res) # res = models.Book.objects.all() """ select_related:會將括號內外鍵字段所關聯的那張表 直接所有拿過來(能夠一次性拿多張表)跟當前表拼接操做 從而下降你跨表查詢 數據庫的壓力 注意select_related括號只能放外鍵字段(一對一和一對多) res = models.Book.objects.all().select_related('外鍵字段1__外鍵字段2__外鍵字段3__外鍵字段4') """ # prefetch_related 不主動連表 res = models.Book.objects.prefetch_related('publish') """ 不主動連表操做(可是內部給你的感受像是連表操做了) 而是將book表中的publish所有拿出來 在取publish表中將id對應的全部的數據取出 res = models.Book.objects.prefetch_related('publish') 括號內有幾個外鍵字段 就會走幾回數據庫查詢操做 """ for r in res: print(r.publish.name)
我的口水總結:
select_related:
會將括號內外鍵字段所關聯的那張表 直接所有拿過來(能夠一次性拿多張表)跟當前表拼接操做
從而下降你跨表查詢 數據庫的壓力
select_related括號只能放外鍵字段(一對一和一對多)
prefetch_related:
不主動連表操做(可是內部給你的感受像是連表操做了) 而是將book表中的publish所有拿出來 在取publish表中將id對應的全部的數據取出
括號內有幾個外鍵字段 就會走幾回數據庫查詢操做
class MyChar(models.Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): return 'char(%s)'%self.max_length
django2注意點:
外鍵字段 當你在使用django2.X版本的時候 在創建外鍵關係時(*****) 須要你手動添加幾個關鍵點參數 models.cascade db_constraints