Django模型層:單表、多表操作、F與Q查詢
DJango模型層
單表操作
使用有幾步:
- settings.py中配置連線資料庫的地址,埠
- 在init.py中使用pymysql
- 在models.py裡寫類,一個類對應一個表,寫屬性
- 資料庫遷移命令,第一個命令是紀錄,第二個命令才是真正的資料庫同步
- 匯入models到views,開始使用
# models.py # 建立單表 from django.db import models class User(models.Model): # 類名就是表名,必須繼承models.Model name = models.CharField(max_length=32) # charfield必須指定最大長度,否則報錯 age = models.IntegerField() # 建立數字欄位 register_time = models.DateField(auto_now=True) # 建立日期物件,這個欄位有兩個重要的引數 # auto_now 每次操作資料的時候自動更新該欄位為 # auto_now_add,建立的時候紀錄時間,只要不人為修改,就會一直不變
當沒有建立主鍵欄位(primary_key=True)的時候,orm會自動幫你建立一個名為id的主鍵欄位
執行兩條資料庫遷移命令,接下來就可以在檢視中或測試指令碼中使用了
# views.py
from app01 import models
# 先從應用中匯入模型
...
增加資料
# 第一種 res = models.User.objects.create(name='aaa',age=21,register_time='2020-02-22') # models.表名.objects.create() 括號裡面填欄位,日期欄位可以直接寫日期也可以填一個日期物件 # 這個方法有一個返回值,就是被建立的物件本身 # 第二種 user_obj = models.User(name='aaa',age=21,register_time='2020-02-22') user_obj.save()
刪除資料
res = models.User.objects.filter(pk=2).delete()
# 查詢當前表主鍵為2的欄位,刪除
user_obj = models.User.objects.filter(pk=2).first()
user_obj.delete()
修改資料
user_obj = models.User.objects.filter(pk=3).update(name='bbb')
orm其他的api
<1> all(): 查詢所有結果 <2> filter(**kwargs): 它包含了與所給篩選條件相匹配的物件 <3> get(**kwargs): 返回與所給篩選條件相匹配的物件,返回結果有且只有一個,如果符合篩選條件的物件超過一個或者沒有都會丟擲錯誤。 <4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的物件 <5> order_by(*field): 對查詢結果排序('-id') <6> reverse(): 對查詢結果反向排序 <8> count(): 返回資料庫中匹配查詢(QuerySet)的物件數量。 <9> first(): 返回第一條記錄 <10> last(): 返回最後一條記錄 <11> exists(): 如果QuerySet包含資料,就返回True,否則返回False <12> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,執行後得到的並不是一系列 model的例項化物件,而是一個可迭代的字典序列 <13> values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列 <14> distinct(): 從返回結果中剔除重複紀錄
基於雙下劃線的模糊查詢
Book.objects.filter(price__in=[100,200,300])
Book.objects.filter(price__gt=100) # 大於
Book.objects.filter(price__lt=100) # 小於
Book.objects.filter(price__gte=100) # 大於等於
Book.objects.filter(price__lte=100) # 小於等於
Book.objects.filter(price__range=[100,200])
Book.objects.filter(title__contains="python")
Book.objects.filter(title__icontains="python")
Book.objects.filter(title__startswith="py")
Book.objects.filter(pub_date__year=2012)
多表操作
表與表之間的關係有一對一,一對多,多對多
以圖書,出版社,作者舉例
一本圖書只能有一個出版社,一個出版社出版多本書
- 書----出版社 :一對多
一本書有多個作者,一個作者可以寫多本書
- 書----作者 : 多對多關係
作者與作者資訊是一對一關係
建立外來鍵
一對多
models.ForeignKey()
# 書與出版社一對多外來鍵
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
# 建立外來鍵欄位publish,其中
# to:關聯的表名
# to_field:要關聯的表的欄位名稱,與publish表中的nid欄位關聯
# on_delete,刪除表中的資料時,當前表與其關聯的資料的行為
# models.CASCADE,刪除關聯資料,與之關聯也刪除
# models.SET_NULL,刪除關聯資料,與之關聯的值設定為null(前提FK欄位需要設定為可空)
# models.SET_DEFAULT,刪除關聯資料,與之關聯的值設定為預設值(前提FK欄位需要設定預設值)
一對一
models.OneToOneField()
# 作者資訊與作者表,一對一關係
author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)
# 關聯的表明:AuthorDetail,關聯的欄位nid,該欄位唯一,刪除表中的資料,authordetail中對應的author也刪除
多對多
authors=models.ManyToManyField(to='Author')
orm多對多關係並沒有真正的關聯,宣告一個ManyToMany欄位後,orm會幫我們建立一張中間表
多表新增表紀錄
一對多
方式1:
publish_obj=Publish.objects.get(nid=1)
book_obj=Book.objects.create(title="",publishDate="2012-12-12",price=100,publish=publish_obj)
方式2:
book_obj=Book.objects.create(title="",publishDate="2012-12-12",price=100,publish_id=1)
多對多
# 當前生成的書籍物件
book_obj=Book.objects.create(title="追風箏的人",price=200,publishDate="2012-11-12",publish_id=1)
# 為書籍繫結的做作者物件
yuan=Author.objects.filter(name="yuan").first()
# 在Author表中主鍵為2的紀錄
egon=Author.objects.filter(name="alex").first()
# 在Author表中主鍵為1的紀錄
# 繫結多對多關係,即向關係表book_authors中新增紀錄
book_obj.authors.add(yuan,egon)
# 將某些特定的 model 物件新增到被關聯物件集合中。=======book_obj.authors.add(*[])
多對多關係常用api
book_obj.authors.remove() # 將某個特定的物件從被關聯物件集合中去除
# book_obj.authors.remove(*[])
book_obj.authors.clear() #清空被關聯物件集合
book_obj.authors.set() #先清空再設定
基於物件的跨表查詢
查詢兩次,先拿到一個物件,再點再查一次得到結果
一對多
一對多的關係,外來鍵欄位建在多的一方,正向查詢就是從有外來鍵欄位的這邊查另一邊:書表查出版社表
# 查詢主鍵為1的書籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主鍵為1的書籍物件關聯的出版社物件
print(book_obj.publish.city)
正向查詢,直接使用點 . 即可
publish=Publish.objects.get(name="蘋果出版社")
#publish.book_set.all() : 與蘋果出版社關聯的所有書籍物件集合
book_list=publish.book_set.all()
for book_obj in book_list:
print(book_obj.title)
反向查詢,使用 要查詢的表_set()
查詢
一對一查詢
正向,反向都用點方法
# 正向查詢
egon=Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)
# 通過作者表查詢作者資訊表的電話號碼
# 反向查詢
# 查詢所有住址在北京的作者的姓名
authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
print(obj.author.name)
多對多查詢
# 眉所有作者的名字以及手機號
book_obj=Book.objects.filter(title="眉").first()
authors=book_obj.authors.all()
for author_obj in authors:
print(author_obj.name,author_obj.authorDetail.telephone)
# 查詢egon出過的所有書籍的名字
author_obj=Author.objects.get(name="egon")
book_list=author_obj.book_set.all()
#與egon作者相關的所有書籍
for book_obj in book_list:
print(book_obj.title)
基於雙下劃線的跨表查詢
使用兩個下劃線來連結模型(model)間關聯欄位的名稱,直到最終連結到你想要的model 為止
一對多
表名__欄位名
# 練習: 查詢蘋果出版社出版過的所有書籍的名字與價格(一對多)
# 正向查詢 按欄位:publish
queryResult=Book.objects.filter(publish__name="蘋果出版社").values_list("title","price")
# 出版社表__出版社名
# 反向查詢 按表名:book
queryResult=Publish.objects.filter(name="蘋果出版社").values_list("book__title","book__price")
# 查詢的本質一樣,就是select from的表不一樣
多對多
# 練習: 查詢alex出過的所有書籍的名字(多對多)
# 正向查詢 按欄位:authors:
queryResult=Book.objects.filter(authors__name="yuan").values_list("title")
# 反向查詢 按表名:book
queryResult=Author.objects.filter(name="yuan").values_list("book__title","book__price")
連續跨表案例
# 查詢人民出版社出版過的所有書籍的名字以及作者的姓名
# 正向查詢
queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
# 反向查詢
queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")
F與Q查詢
F查詢
F() 的例項可以在查詢中引用欄位,來比較同一個 model 例項中兩個不同欄位的值
from django.db.models import F
# 需要先匯入F
Book.objects.filter(commnetNum__lt=F('keepNum'))
# book表中,commentNum<keepNum的資料
Django 支援F()物件之間以及F()物件和常數之間的加減乘除和取模的操作
# 查詢評論數大於收藏數2倍的書籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)
修改操作也可以使用F函式,比如將每一本書的價格提高30元:
Book.objects.all().update(price=F("price")+30)
Q查詢
filter()
等方法中的關鍵字引數查詢都是一起進行“AND” 的。 如果你需要執行更復雜的查詢(例如OR
語句),你可以使用Q 物件
。
from django.db.models import Q
Q(title__startswith='Py')
Q
物件可以使用&
和|
操作符組合起來。當一個操作符在兩個Q
物件上使用時,它產生一個新的Q
物件。
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
等同於下面的SQL WHERE
子句:
WHERE name ="yuan" OR name ="egon"
你可以組合&
和|
操作符以及使用括號進行分組來編寫任意複雜的Q
物件。同時,Q
物件可以使用~
操作符取反,這允許組合正常的查詢和取反(NOT
) 查詢:
查詢函式可以混合使用Q 物件
和關鍵字引數。所有提供給查詢函式的引數(關鍵字引數或Q
物件)都將“AND”在一起。但是,如果出現Q
物件,它必須位於所有關鍵字引數的前面。例如:
bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")
一些例子
# 查詢評論數大於閱讀數的書籍
from django.db.models import F,Q
ret=Book.objects.filter(commit_num__gt=F('reat_num'))
print(ret)
# 把所有書籍的價格加10
Book.objects.all().update(price=F('price')+10)
# ----Q函式,描述一個與,或,非的關係
# 查詢名字叫紅樓夢或者價格大於100的書
ret=Book.objects.filter(Q(name='紅樓夢')|Q(price__gt=100))
print(ret)
# 查詢名字叫紅樓夢和價格大於100的書
ret = Book.objects.filter(Q(name='紅樓夢') & Q(price__gt=100))
print(ret)
# # 等同於
ret2=Book.objects.filter(name='紅樓夢',price__gt=100)
print(ret2)
# 也可以Q套Q
# 查詢名字叫紅樓夢和價格大於100 或者 nid大於2
ret=Book.objects.filter((Q(name='紅樓夢') & Q(price__gt=100))|Q(nid__gt=2))
print(ret)
# ----非
ret=Book.objects.filter(~Q(name='紅樓夢'))
print(ret)
# Q和鍵值對聯合使用,但是鍵值對必須放在Q的後面(描述的是一個且的關係)
# 查詢名字不是紅樓夢,並且價格大於100的書
ret=Book.objects.filter(~Q(name='紅樓夢'),price__gt=100)
print(ret)