Django微講解(七)
阿新 • • 發佈:2022-05-18
Django微講解(七)
聚合查詢
我們在講資料庫的聚合查詢的時候,講了資料庫的聚合函式,常用就是最大值'max'、最小值'min'、求和'sum'、計數'count'、 平均值'avg',我們的Django ORM聚合查詢使用的也是這些關鍵字,只不過資料庫的聚合函式是需要分組之後才可以使用的,而Django ORM 的聚合函式沒有分組也可以使用聚合函式,預設整體的一個表就是一組。 from django.db.models import Max,Min,Count,Sum,Avg res = models.Book.objects.aggregate(Max('price')) print(res) 使用聚合查詢的關鍵字是'aggregate'
分組查詢
資料庫的分組查詢使用的是group by關鍵字,Django ORM使用的關鍵字是'annotate',ORM在執行分組操作的時候,有的計算機 會報錯,報錯的話可以去修改'sql_mode',移除'only_full_group_by'即可。 # 1.統計每本書的作者個數 res = models.Book.objects.annotate(auhtor_num=Count('authors__pk')).values('title','auhtor_num') print(res) # 2.統計每個出版社賣的最便宜的書的價格 res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') print(res) # 3.統計不止一個作者的圖書 res = models.Book.objects.annotate(author_count=Count('authors__pk')).filter(author_count__gte=2).values('title','author_count') print(res) # 4.統計每個作者出的書的總價格 res = models.Author.objects.annotate(price_num=Sum('book__price')).values('name','price_num') print(res) # 5.統計每個出版社主鍵值對應的書籍個數 ''' 上述四個練習題都是以表為單位分組的,如果想要以表中的某個欄位分組,只需要在'annotate'關鍵字前面點'values'給某個欄位進行分組即可 ''' res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num') print(res)
往已經存在資料的表中新增欄位
當表中已經存在資料的情況下,想要在新增額外欄位,就需要指定該欄位的預設值,或者指定該欄位的值可以為null
方式一:
可以給額外新增的欄位加一個預設值,關鍵字是'default'
示例:age = models.IntegerField(default=25)
方式二:
設定額外新增欄位的值可以為null
示例:age = models.IntegerField(null=True)
方式三:
可以在遷移命令的提示中直接給預設值
F查詢
F可以幫我們取到表中某個欄位對應的值來當做我們的篩選條件,而不是自定義常量的條件,實現了動態比較的效果,Django還支 持F物件之間以及F物件與常數之間的加減乘除和取模的操作。 # 1.查詢庫存大於銷量的書籍 from django.db.models import F res = models.Book.objects.filter(kucun__gt=F('xiaoliang')) print(res) # 2.將所有書的價格提升1000塊 res = models.Book.objects.update(price=F('price') + 1000) print(res) # 3.將所有書的名稱後面加上_爆款字尾 ''' 想要修改char欄位的值,不可以用上述的方法,可以使用下面ORM專門提供的方法 ''' from django.db.models.functions import Concat from django.db.models import Value,F models.Book.objects.update(title=Concat(F('title'),Value('_iii')))
Q查詢
filter()方法中逗號隔開的條件是'and'的關係,是沒有辦法直接修改的,所以我們就可以使用Q物件,支援邏輯運算子,'管道
符'(|)就是'or'關係,在Q物件前面加'~'就是'not'的關係。
# 1.查詢價格大於20000或者賣出大於1000的書籍
from django.db.models import Q
res = models.Book.objects.filter(Q(price__gt=20000)|Q(xiaoliang__gt=1000))
print(res) # 管道符是or關係
# 2.查詢價格小於20000或者庫存小於1000的書籍
res = models.Book.objects.filter(~Q(price__gte=20000)|~Q(kucun__gte=1000))
print(res) # ~是not關係
# 3.Q物件進階用法
q_obj = Q() # Q方法其實是一個類,我們先產生一個q_obj物件
q_obj.connector = 'or' # 預設是and關係,可以改沒or
q_obj.children.append(('price__gt',20000))
q_obj.children.append(('kucun__gt',1000))
res = models.Book.objects.filter(q_obj)
print(res)
ORM查詢優化
ORM查詢預設都是惰性查詢,能不消耗資料庫資源就不消耗,ORM查詢預設自帶分頁功能,儘量減輕單次查詢資料的壓力
# only
only會產生物件結果集,物件點括號內出現的欄位不會再次查詢資料庫
res = models.Book.objects.only('title','price')
for obj in res:
print(obj.title)
print(obj.price)
# print(obj.xiaoliang) # 也可以點括號以外的,但是會再次查詢資料庫,增加了資料庫的壓力
# defer
defer也會產生物件結果集,物件點括號之外的欄位不會再次查詢資料庫
res = models.Book.objects.defer('title','price')
for obj in res:
print(obj.xiaoliang)
# print(obj.price) # 也可以點括號內的,但是會再次查詢資料庫,增加資料庫的壓力
# select_related
select_related括號內只能傳外來鍵欄位,只能傳一對一和一對多欄位,不能傳多對多欄位,內部原理就是直接連表,然後將連
接之後的表中所有的資料全部封裝到資料物件中,然後物件就可以通過正反向查詢,內部不會再次查詢資料庫,不會增加資料庫的壓力。
res = models.Book.objects.select_related('publish')
for obj in res:
print(obj.title)
print(obj.price)
print(obj.publish.name)
print(obj.publish.addr)
# prefetch_related
prefetch_related括號內只能傳外來鍵欄位,只能傳一對一和一對多欄位,不能傳多對多欄位,內部原理是將多次查詢之後的結
果封裝到資料物件當中,然後物件就可以通過正反向查詢,內部不會再次查詢資料庫,不會增加資料庫的壓力。
res = models.Book.objects.prefetch_related('publish')
for obj in res:
print(obj.title)
print(obj.price)
print(obj.publish.name)
print(obj.publish.addr)
ORM常見欄位
# 1.AutoField
int自增列,必須填入引數 primary_key=True。當model中如果沒有自增列,則自動會建立一個列名為id的列。
# 2.IntegerField
整型int
# 3.CharField
字元型別,必須提供max_length引數, max_length表示字元長度,對應的是資料庫中的varchar型別,沒有設定對應char型別
的欄位,但是Django允許我們自定義新的欄位。
# 4.DecimalField
10進位制小數
# 5.DateField
日期欄位,日期格式 YYYY-MM-DD,相當於Python中的datetime.date()例項。
# 6.DateTimeField
日期時間欄位,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當於Python中的datetime.datetime()例項。
# 7.BigIntergerField
整型bigint
# 8.BooleanField
傳佈爾值,對應的是0和1
# 9.TextField
儲存大段文字
# 10.FileField
傳檔案自動儲存到指定位置並存檔案路徑
# 11.EmailField
本質還是varchar型別
ORM重要引數
# 1.primary_key
主鍵
# 2.max_length
欄位最大長度
# 3.verbose_name
註釋
# 4.null
是否允許為空
# 5.default
設定預設值
# 6.max_digits
小數總長度
# 7.decimal_places
小數位長度
# 8.unique
如果設定為unique=True 則該欄位在此表中必須是唯一的 。
# 9.db_index
如果db_index=True 則代表著為此欄位設定索引。
# 10.auto_now
配置上auto_now=True,每次更新資料記錄的時候會更新該欄位。
# 11.auto_now_add
配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫。
# 12.choices
用於可以被例舉完全的資料
# 13.to
設定要關聯的表
# 14.to_field
設定要關聯的表的欄位
# 15.db_constraint
是否在資料庫中建立外來鍵約束,預設為True。
'''
外來鍵欄位中使用related_name引數可以修改正向查詢的欄位名
'''
choices示例:
models.py檔案:
class Info(models.Model):
username = models.CharField(max_length=255)
password = models.IntegerField()
gender_choies = (
(1,'nan'),
(2,'nv'),
(3,'bian')
)
gender = models.IntegerField(choices=gender_choies)
test.py檔案:
res = models.Info.objects.filter(pk=1).first()
print(res.get_gender_display())
事務操作
# MySQL事務四大特性
原子性、一致性、永續性、獨立性
# MySQL事務的關鍵字
開啟事務:start transcation
事務回滾:rollback
確認事務:commit
# ORM事務操作
from django.db import transaction
try:
with transaction.atomic(): # with語句結束,事務結束
pass # 事務程式碼
except Exception:
pass
ORM執行原生SQL
# 方式1
from django.db import connection, connections
cursor = connection.cursor()
cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
cursor.fetchone()
# 方式2
models.UserInfo.objects.extra(
select={'newid':'select count(1) from app01_usertype where id>%s'},
select_params=[1,],
where = ['age>%s'],
params=[18,],
order_by=['-age'],
tables=['app01_usertype']
)
多對多建立方式
# 1.全自動
全自動就是ORM自動建立第三張表,但是沒有辦法擴充套件第三張表的欄位
示例:authors = models.ManyToManyField(to='Author')
# 2.全手動
第三張表可以完全自定義,擴充套件性高,但是不能使用外來鍵方法和正反向查詢
示例:
class Book(models.Model):
title = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author')
# 3.半自動
可以使用正反向查詢,第三張表還可以擴充套件,但是不能使用add、set、remove、clear這四種方法
示例:
'''
多對多建在任意一方都可以,如果建在Author表,欄位順序互換即可
'''
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(
to='Author',
through='Book2Author', # 指定表
through_fields=('book','author') # 指定欄位
)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
這裡是IT小白陸祿緋,歡迎各位大佬的指點!!!