Python學習第149天(Django之模型層1)
阿新 • • 發佈:2020-08-09
一.ORM 中常用欄位和引數
1.常用欄位
自增列,可以將其理解為ID主鍵欄位,注意的是必須填入引數 primary_key=True
當model中如果沒有自增列,則自動會建立一個列名為id的列
id = models.AutoField(primary_key=True)
IntegerField
整形欄位,圍在 -2147483648 to 2147483647。(一般不用它來存手機號(位數也不夠),直接用字串存,)
kucun = models.IntegerField() # 可以不指定引數
CharField
字元欄位,必須提供max_length引數, max_length表示字元長度。
title = models.CharField(max_length=255) # 注意:Django中的CharField對應的MySQL資料庫中的varchar型別
DecimalField
小數字段,必須提供max_digits引數和decimal_places引數
price = models.DecimalField(max_digits=8,decimal_places=2)
DateField
日期欄位,日期格式 YYYY-MM-DD,相當於Python中的datetime.date()例項。
publish_date = models.DateField(auto_now_add=True)
DateTimeField
日期時間欄位,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()例項。
2.欄位引數
verbose_name
給欄位命名
null
用於表示某個欄位可以為空。null=True
unique
如果設定為unique=True 則該欄位在此表中必須是唯一的 。
db_index
如果db_index=True 則代表著為此欄位設定索引
default
為該欄位設定預設值
關於時間引數
1.auto_now_add
配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫。
2.auto_now
配置上auto_now=True,每次更新資料記錄的時候會更新該欄位。
3.關係欄位
1.ForeignKey
外來鍵型別在ORM中用來表示外來鍵關聯關係,一般把ForeignKey欄位設定在 '一對多'中'多'的一方。
ForeignKey可以和其他表做關聯關係同時也可以和自身做關聯關係。
欄位引數
1.to 設定要關聯的表
publish = models.ForeignKey(to='Publish') # 預設是跟publish表的主鍵欄位做的一對多外來鍵關聯
2.to_field
設定要關聯的表的欄位
3.on_delete
當刪除關聯表中的資料時,當前表與其關聯的行的行為。
2.OneToOneField
通常一對一欄位用來擴充套件已有欄位。(通俗的說就是一個人的所有資訊不是放在一張表裡面的,簡單的資訊一張表,隱私的資訊另一張表,之間通過一對一外來鍵關聯)
ps:可以用 ForeignKey(unique=True) 代替
欄位引數
1.to
設定要關聯的表。
author_detail = models.OneToOneField(to='AuthorDetail')
2.to_field
設定要關聯的欄位。
3.on_delete
當刪除關聯表中的資料時,當前表與其關聯的行的行為。
ManyToManyField
多對多欄位
# 是虛擬欄位,表中不會顯式,
作用:
1.告訴orm自動建立第三種表
2.幫助orm跨表查詢
authors = models.ManyToManyField(to='Author')
二.表操作
表操作之 欄位增刪改查
增
當一張表已經創建出來之後 後續還想新增欄位,可以有兩種方式
(1)給新增的欄位設定預設值
addr = models.CharField(max_length=32,default='China') # default該欄位預設值
(2)給新增的欄位設定成可以為空
age = models.IntegerField(null=True) # 該欄位允許為空
刪
刪除欄位 直接在models.py中註釋該欄位 然後重新執行兩條命令即可注意:執行完之後 表中該欄位所對應的所有的資料全部刪除並且一般情況下 基本是不會用到真正意義上的刪除
1.表操作之 單表
查:必知必會13條
<1> all(): 查詢所有結果
<2> filter(**kwargs): 它包含了與所給篩選條件相匹配的物件
<3> get(**kwargs): 返回與所給篩選條件相匹配的物件,返回結果有且只有一個,如果符合篩選條件的物件超過一個或者沒有都會丟擲錯誤
<4> exclude(**kwargs): 它包含了與所給篩選條件不匹配的物件
<5> values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,執行後得到的並不是一系列model的例項化物件,而是一個可迭代的字典序列
<6> values_list(*field): 它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
<7> order_by(*field): 對查詢結果排序
<8> reverse(): 對查詢結果反向排序,請注意reverse()通常只能在具有已定義順序的QuerySet上呼叫(在model類的Meta中指定ordering或呼叫order_by()方法)。
<9> distinct(): 從返回結果中剔除重複紀錄(如果你查詢跨越多個表,可能在計算QuerySet時得到重複的結果。此時可以使用distinct(),注意只有在PostgreSQL中支援按欄位去重。)
<10> count(): 返回資料庫中匹配查詢(QuerySet)的物件數量。
<11> first(): 返回第一條記錄
<12> last(): 返回最後一條記錄
<13> exists(): 如果QuerySet包含資料,就返回True,否則返回False
總結
# 返回QuerySet物件的方法有 all() filter() exclude() order_by() reverse() distinct() # 特殊的QuerySet values() 返回一個可迭代的字典序列 values_list() 返回一個可迭代的元祖序列 # 返回具體物件的 get() first() last() # 返回布林值的方法有: exists() # 返回數字的方法有 count()
查:雙下劃線
1.大於/小於 models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值 2.in models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的資料 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in 3.模糊查詢 models.Tb1.objects.filter(name__contains="ven") # 獲取name欄位包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感 4.範圍 models.Tb1.objects.filter(id__range=[1, 3]) # id範圍是1到3的,等價於SQL的bettwen and 5.以什麼開頭 以什麼結尾 欄位__startswith 欄位__endswith 6.按年查詢 models.Class.objects.filter(create_time__year=2017) # date欄位可以通過在其後加__year,__month,__day等來獲取date的特點部分資料
增
<1> create()
1.create方法能夠新增資料 並且有一個返回值
2.返回值就是新增的資料物件本身
res = models.User.objects.create(username=username,password=password) # insert into user(username,password) values(username,password) print(res) >>> User object print(res.password) print(res.username)
<2> 物件方法
user_obj = models.User(username=username, password=password) user_obj.save()
刪
models.User.objects.filter(條件).delete() # delete from user where id = delete_id; ps: querySet 物件可以用.delete() 方法
改
<1> update()
models.User.objects.filter(id=edit_id).update(username=username,password=password) # update user set username = username,password = password where id = edit_id """ filter拿到是一個列表 filter操作其實都是批量操作 如果filter結果列表中有多個數據 那麼會一次性全部修改 類似於for迴圈一個個修改 """ ps: querySet 物件可以用.update() 方法
<2> 物件方法
edit_obj.username = username edit_obj.password = password edit_obj.save() """ 第二種方式會從頭到尾將所有的欄位全部修改一遍 效率極低,不推薦使用 """
2.表操作之 多表
<1>.一對多 表關係的增刪改
# 一對多 欄位資料的增刪改查 # 增 # 1 傳出版社的id數字 models.Book.objects.create(title='三國演義', prince=189.99, publish_id=1) # 2 傳出版社物件 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='紅樓夢', prince=999.99, publish=publish_obj) # 改 # 1 傳出版社的id數字 models.Book.objects.filter(pk=1).update(publish_id=3) # 2 傳出版社物件 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() # 預設級聯更新級聯刪除
<1>.多對多 表關係的增刪改
# 多對多表關係 欄位資料的增刪改 # 增 給主鍵為1的書籍新增兩個作者 # 1 傳作者的id數字 book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.authors) # 物件點選多對多虛擬欄位 會直接跨到多對多的第三張表 book_obj.authors.add(1) book_obj.authors.add(2, 3) # 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.add(author_obj) book_obj.authors.add(author_obj1,author_obj2) """ add() 是給書籍新增作者,括號內既可以傳數字也可以傳物件 並且支援一次性傳多個,逗號隔開即可 """ # 改 將主鍵為1的書籍物件 作者修改為2,3 # 1 傳作者的id數字 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.set([2,]) book_obj.authors.set([2,3]) # 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.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括號內不需要傳任何引數 """
<3>跨表查詢
正向與反向的概念
# 一對一 # 正向: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) # 物件點外來鍵欄位直接跳到對應的表裡 2.反向 # 查詢出版社是東方出版社出版的書籍 publish_obj = models.Publish.objects.filter(name='東方出版社').first() # print(publish_obj.book_set) # app01.Book.None print(publish_obj.book_set.all()) # 總結 """ 當你反向查詢的結果是多個的時候,就需要 表名_set.all() 否則直接表明小寫即可 """
基於雙下劃線的查詢(連表操作)
本質: left join
inner join
right join
union
# 查詢xiongda作者的手機號 1.正向 res=models.Author.objects.filter(name='xiongda').values('author_detail__phone','author_detail__addr') print(res)
(解釋:author_detail 是 Author表中關聯AuthorDetail表的外來鍵欄位(外來鍵欄位可以理解為就是被關聯表中的一行資料即一條記錄)
author_detail__phone 就是拿到了xiongda對應在AuthourDetail表中的那條記錄裡的phone欄位的值) 2.反向 res1 = models.AuthorDetail.objects.filter(author__name='xiongda').values('phone') print(res1)
聚合查詢(aggregate)
# 統計所有書的總價格 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'))
分組查詢(annotate)
from django.db.models import Max, Min, Count, Avg, Sum # 統計每一本書的作者個數 res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num','title') # 統計出每個出版社賣的最便宜的書的價格 res = models.Publish.objects.annotate(mmp =Min('book__price')).values('name','mmp') # 統計不止一個作者的圖書 res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1) ps: models 後面跟的是什麼就按什麼分組
F 查詢
F查詢的本質就是從資料庫中獲取某個欄位的值 """ 之前查詢等號後面的條件都是我們人為輸入的 現在變成了需要從資料庫中獲取資料放在等號後面,實現了動態比較的效果 """
from django.db.models import F # 查詢庫存數量大於賣出數量的書 res = models.Book.objects.filter(kucun__gt=F('maichu')) # 將書籍庫存數全部增加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')+'新款') # 不能這麼寫
Q 查詢
filter() 等方法中逗號隔開的條件是與的關係。 如果你需要執行更復雜的查詢(例如OR語句),你可以使用Q物件。 | 代表或的關係 ~ 是取反
from django.db.models import Q # 查詢 賣出數大於100 或者 價格小於100塊的 models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100)) # 查詢 書名不是 三國演義的書 或者 價格等於444元的 models.Book.objects.filter(~Q(title='三國演義')|Q(price=444)) # 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)
還是喜歡大螢幕寫東西!!!