一 聚合查詢
1. 級聯
級聯刪除
操作外鍵字段管理數據的時候
書跟出版社是一對多關系,外鍵字段在書那,如果把出版社刪了,所對應的書也會自動刪除
級聯更新
如果把出版社主鍵值改變,那么書籍表中的出版社主鍵值也會更新改變
2. 聚合函數
- 聚合函數必須用在分組之后
- 沒有分組其實默認整體就是一組
Max Min Sum Sum Avg Count
使用 aggregate
-
關鍵字 aggregate
-
還需要導入模塊
from django.db.models import Max,Min,Sum,Sum,Avg,Count
只要跟數據庫相關的功能,基本上都在django.db.models里面
如果不在,可能直接在django.db中
使用場景
- 單獨使用:不分組,只聚合結果(aggregate)
- 分組使用: 按字段分組,可分組字段與聚合結果(annotate)
1.篩選出價格最高的書籍的
res = models.Book.objects.aggregate(mr = Max('price'))
print(res)
2.求書籍總價格
res = models.Book.objects.aggregate(sm = Sum('price'))
print(res)
3.求書籍平均價格
res = models.Book.objects.aggregate(av = Avg('price'))
print(res)
4.一起使用
res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price'))
print(res)
3. 分組查詢
語法
values('分組字段').annotate(別名=聚合函數('字段')).filter(聚合字段別名條件).values('取分組字段', '取聚合字段別名')
什么時候需要分組
- 統計每一個部門的平局薪資
- 統計每一個部門的男女比例
- 統計某一數據的組別內數據
使用 annotate
-
關鍵字
annotate
-
借助於聚合函數
from django.db.models import Max,Min,Sum,Sum,Avg,Count
-
django中models后面點什么,就按什么分組
代碼
1.統計每一本書的作者個數 書名 和對應的作者人數
res = models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num')
print(res)
2.統計出每個出版社賣的最便宜的書的價格 出版社的名字 價格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
print(res)
按照其他字段分組
res = models.Publish.objects.values('想要分組的字段名').annotate(min_price=Min('book__price')).values('name','min_price')
print(res)
3.統計不止一個作者的圖書
1.先拿書及對應的作者數
2.再篩選出大於一的圖書 書名 作者數目
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num')
print(res)
4.查詢各個作者出的書的總價格 作者名字 總價格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
print(res)
4. F與Q查詢
F查詢
- 通過字段名獲取可以直接做運算的查詢結果
- F基於 F('字段條件')
導入
from django.db.models import F
使用
- 后面的條件是來自於數據庫的其他字段值
- 更改字符數操作,需要借助於Concat方法,在后面拼接字符串
from django.db.models import F,Q
1. 查詢庫存數大於賣出數的書籍
res = models.Book.objects.filter(kun_cun__gt = F('mai_cun')).values('title') # 后面的條件是來自於數據庫的其他字段值
print(res)
2. 將所有書的價格上漲100塊
models.Book.objects.all().update(price=F('price') + 100)
3.將所有書的名稱后面全部加上 "爆款" 后綴 了解知識點 操作字符串數據需要借助於Concat方法
from django.db.models.functions import Concat
from django.db.models import Value
ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
Q查詢
- 完成邏輯運算方式的查詢
- Q基於 Q('字段條件')
- 三種運算符
&(與) |(或) ~(非)
導入
from django.db.models import Q
使用
1.查詢一下書籍名稱是三國演義 或者 庫存數是500的書籍
res = models.Book.objects.filter(title='三國演義',kun_cun=500) # and關系
res = models.Book.objects.filter(title='三國演義',kun_cun=500) # and關系
res = models.Book.objects.filter(Q(title='三國演義'),Q(kun_cun=500)) # Q包裹之后逗號還是and關系
res = models.Book.objects.filter(Q(title='三國演義') | Q(kun_cun=500)) # |就是or的關系
res = models.Book.objects.filter(~Q(title='三國演義') | Q(kun_cun=500)) # ~就是not關系
print(res)
Q對象高級用法 q.children(('元組'))
按條件查詢時,可以傳字符串進行查詢默認是and關系,更改connector改為or
,對象前加~
取反
q = Q()
q.connector = 'or' # 默認是and 可以改成or
q.children.append(('title','三國演義'))
q.children.append(('kun_cun__gt',500))
res = models.Book.objects.filter(~q) # 取反
print(res)
二 ORM字段及參數
1.ORM字段
常用字段
字段 | 說明 | 字段屬性 |
---|---|---|
AutoField() | 默認自增主鍵(primary_key=True),django會默認建立id字段主鍵 | |
CharField() | 字符類型 | max_length=64,數據長度,必須明確 |
IntegerField() | 整型 | |
DateField() | 年月日時間類型 | -- auto_now=True,數據被更新就會更新時間 -- auto_now_add=True,數據第一次參數時產生 |
DateTimeField() | 年月日小時分鍾秒時間類型 | -- auto_now=True,數據被更新就會更新時間 -- auto_now_add=True,數據第一次參數時產生 |
DecimalField() | 混合精度的小數類型 | -- max_digits=3,限定數字的最大位數(包含小數位) -- decimal_places=2,限制小數的最大位數 |
BooleanField() | 布爾字段,對應數據庫tinyint類型 數據長度只有1位 | 內部只接收0/1或者True/Flase |
TextField | 專門用來存大段文本 | |
FileField | 專門用來文件路徑 | upload_to = '/etc/data',給該字段傳值的時候 直接傳文件對象 |
CharField varchar
IntegerField int
BigIntegerField bigint
EmailField varchar(254)
DateField
DateTimeField
auto_now:每次修改數據的時候 都會自動將當前修改時間更新上去 實時更新
auto_now_add:在創建數據的時候 會將當前時間自動記錄 之后不會自動修改 除非你人為修改
AutoField auto_increment
BooleanField 布爾值
該字段在存儲的時候 你只需要傳布爾值True或False
它會自動存成1/0
TextField 專門用來存大段文本
FileField 專門用來文件路徑 '/etc/data/a.txt'
upload_to = '/etc/data'
給該字段傳值的時候 直接傳文件對象
會自動將文件對象保存到upload_to后面指定的文件路徑中
然后將路徑保存到數據庫
DecimalField(Field)
- 10進制小數
- 參數:
max_digits,小數總長度
decimal_places,小數位長度
DateField和DateTimeField
auto_now_add
配置auto_now_add=True,創建數據記錄的時候會把當前時間添加到數據庫。
auto_now
配置上auto_now=True,每次更新數據記錄的時候會更新該字段。
不常用字段
# 1. BigAutoField():大整型自增
# 2. BigIntegerField():長整型
# 3. EmailField():郵箱字段,擁有/admin/驗證
# 4. FloatField():浮點型小數
# 5. SmallIntegerField():小整型
# 6. TextField():大文本類型
# 7. FileField():文件字段
字段合集
AutoField(Field)
- int自增列,必須填入參數 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必須填入參數 primary_key=True
注:當model中如果沒有自增列,則自動會創建一個列名為id的列
from django.db import models
class UserInfo(models.Model):
# 自動創建一個列名為id的且為自增的整數列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定義自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整數 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整數 0 ~ 32767
IntegerField(Field)
- 整數列(有符號的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整數 0 ~ 2147483647
BigIntegerField(IntegerField):
- 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布爾值類型
NullBooleanField(Field):
- 可以為空的布爾值
CharField(Field)
- 字符類型
- 必須提供max_length參數, max_length表示字符長度
TextField(Field)
- 文本類型
EmailField(CharField):
- 字符串類型,Django Admin以及ModelForm中提供驗證機制
IPAddressField(Field)
- 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制
GenericIPAddressField(Field)
- 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
- 參數:
protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時候,可解析為192.0.2.1,開啟此功能,需要protocol="both"
URLField(CharField)
- 字符串類型,Django Admin以及ModelForm中提供驗證 URL
SlugField(CharField)
- 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下划線、連接符(減號)
CommaSeparatedIntegerField(CharField)
- 字符串類型,格式必須為逗號分割的數字
UUIDField(Field)
- 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
- 參數:
path, 文件夾路徑
match=None, 正則匹配
recursive=False, 遞歸下面的文件夾
allow_files=True, 允許文件
allow_folders=False, 允許文件夾
FileField(Field)
- 字符串,路徑保存在數據庫,文件上傳到指定目錄
- 參數:
upload_to = "" 上傳文件的保存路徑
storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路徑保存在數據庫,文件上傳到指定目錄
- 參數:
upload_to = "" 上傳文件的保存路徑
storage = None 存儲組件,默認django.core.files.storage.FileSystemStorage
width_field=None, 上傳圖片的高度保存的數據庫字段名(字符串)
height_field=None 上傳圖片的寬度保存的數據庫字段名(字符串)
DateTimeField(DateField)
- 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 時間格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值為datetime.timedelta類型
FloatField(Field)
- 浮點型
DecimalField(Field)
- 10進制小數
- 參數:
max_digits,小數總長度
decimal_places,小數位長度
BinaryField(Field)
- 二進制類型
字段合集
ORM字段與MySQL字段對應關系
對應關系:
'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
ORM字段與MySQL字段對應關系
2. 關系字段
ForeignKey():外鍵字段
外鍵類型在ORM中用來表示外鍵關聯關系,一般把ForeignKey字段設置在 '一對多'中'多'的一方。
ForeignKey可以和其他表做關聯關系同時也可以和自身做關聯關系。
字段參數
to
設置要關聯的表
to_field
設置要關聯的表的字段
on_delete
當刪除關聯表中的數據時,當前表與其關聯的行的行為。
models.CASCADE
刪除關聯數據,與之關聯也刪除
db_constraint
是否在數據庫中創建外鍵約束,默認為True。
# 1. ForeignKey():外鍵字段
#-- 字段屬性to關聯模型類
#-- 字段屬性to_field關聯字段,省略默認關聯主鍵
#-- 字段屬性on_delete (外鍵關聯數據被刪除時的操作)
#-- models.CASCADE 級聯刪除
class Book(models.Model):
publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE)
#-- modles.PROTECT 拋出異常
#-- models.SET_NULL 設置空值
#-- models.SET_DEFAULT 設置默認值
#-- models.SET(value)自定義值
#-- 字段屬性related_name自定義反向查詢的字段名,自定義后方向查詢自定義的名字會將默認的類名下划線set覆蓋。
#-- 字段屬性db_constraint=False取消關聯關系,但還可以使用連表查詢
#總結:models.ForeignKey(to='關聯的類名', null=True, on_delete=models.SET_NULL, db_constraint=False, related_name="本類名小寫")
class Test2(models.Model):
name = models.CharField(max_length=20)
test1 = models.ForeignKey(to='Test1', null=True, on_delete=models.SET_NULL, db_constraint=False, related_name="tt")
OneToOneField():一對一外鍵字段
一對一字段。
通常一對一字段用來擴展已有字段。(通俗的說就是一個人的所有信息不是放在一張表里面的,簡單的信息一張表,隱私的信息另一張表,之間通過一對一外鍵關聯)
字段參數
to
設置要關聯的表。
to_field
設置要關聯的字段。
on_delete
當刪除關聯表中的數據時,當前表與其關聯的行的行為。(參考上面的例子)
#2、OneToOneField():一對一外鍵字段
# -- 字段同外鍵
ManyToManyField():多對多關系字段
#3、ManyToManyField():多對多關系字段
#-- 字段屬性to關聯模型類
#-- 字段屬性through關聯關系類
#-- 字段屬性through_fields關聯關系表中(本身類名小寫字段, 關聯表類名小寫字段)
class MyBook(models.Model):
my_author = models.ManyToManyField(to='MyAuthor', through='MyBook_MyAuthor', through_fields=('mybook', 'myauthor'))
class MyAuthor(models.Model):
name = models.CharField(max_length=20)
class MyBook_MyAuthor(models.Model):
mybook = models.ForeignKey(to="MyBook", null=True, on_delete=models.SET_NULL, db_constraint=False)
myauthor = models.ForeignKey(to='MyAuthor', null=True, on_delete=models.SET_NULL, db_constraint=False)
time = models.DateField()
3. 字段屬性
null
用於表示某個字段可以為空
#1. null:默認為False,True表示字段可為null,與數據庫相關
a1 = models.CharField(max_length=20) # 插入數據時該字段必須賦值
a2 = models.CharField(max_length=20, null=True) # 插入數據時可以為空
unique
如果設置為unique=True 則該字段在此表中必須是唯一的
db_index
如果db_index=True 則代表着為此字段設置索引。
default
為該字段設置默認值。
#1. null:默認為False,True表示字段可為null,與數據庫相關
a1 = models.CharField(max_length=20) # 插入數據時該字段必須賦值
a2 = models.CharField(max_length=20, null=True) # 插入數據時可以為空
#2. blank:默認為False,True表示字段可為空, 與表單驗證相關
#3. choice:可選的,限制了該選項的字段值必須是所指定的choice中的一個:
-- sex = models.SmallIntegerField(choices=((1, '男'), (2, "女")))
-- obj.get_sex_display()
#4. db_column:自定義字段名
sex = models.SmallIntegerField(choices=choices, default=0, db_column='gender')
# 他只是將數據庫中的字段變為gender,在django中若要查詢該字段的值仍需要輸入sex,因此不常用,不建議使用。
#5. db_index:如果為True的話,設置索引
#6. default:字段默認值
#7. editable:默認為True,若為False,則不會在/admin/界面顯示
#8. primary_key:若設置為True,則表示將該字段設置為主鍵。一般情況下django默認會設置一個自增長的id主鍵。
#9. unique:若設置為True,該字段值不可重復
4. 自定義字段類型
class MyCharField(model.Field):
def __init__(self,max_length,*args,**kwargs):
重新調用父類的方法
super().__init__(max_length=max_length,*args,**kwargs)
調用創建庫字段時的類型方法
def db_type(self,connection):
return'char(%s)' % self.max_length
三 斷開關聯的關系表
1. 斷開外鍵關聯的ForeignKey使用
# 1、不使用ForeignKey方式斷開關聯(即建表的時候就不讓其擁有自動關聯關系,而是手動的靠創建數據時的數據錄入建立關聯關系),查詢的時候不再支持Django ORM連表查詢語法
class Publish(models.Model):
name = models.CharField(max_length=20)
class Book(models.Model):
name = models.CharField(max_length=20)
# 字段需要寫_id來表示相關表的字段信息
publish_id = models.IntegerField()
# *****
# 2、使用ForeignKey方式用db_constraint=False字段屬性斷開關聯,依然支持Django ORM連表查詢語法,建議使用
class Publish(models.Model):
name = models.CharField(max_length=20)
class Book(models.Model):
name = models.CharField(max_length=20)
# 字段不需要寫_id來表示相關表的字段信息,ORM會自動添加
publish = models.ForeignKey(to='Publish', null=True, on_delete=models.SET_NULL, db_constraint=False)
2.斷開關聯的多對多自動創建關系表
# 使用ManyToManyField方式用db_constraint=False字段屬性斷開關聯,依然支持Django ORM連表查詢語法,建議使用
class MyBook(models.Model):
name = models.CharField(max_length=20)
my_author = models.ManyToManyField(to='MyAuthor', db_constraint=False)
class MyAuthor(models.Model):
name = models.CharField(max_length=20)
3. 斷開關聯的多對多手動創建關系表
手動創建關系表的好處:手動創建關系表可以讓關系表可以擁有更多的自身的字段,同時通過關系表類名可以直接獲取第三張表
1、和自動建立關系表類似,依然支持Django ORM連表查詢語法(多對多借助關系表連表查詢)
class Book(models.Model):
name = models.CharField(max_length=20)
class Author(models.Model):
name = models.CharField(max_length=20)
class Book_Author(models.Model):
book = models.ForeignKey(to="Book", null=True, on_delete=models.SET_NULL, db_constraint=False)
author = models.ForeignKey(to='Author', null=True, on_delete=models.SET_NULL, db_constraint=False)
time = models.DateField()
2、手動創建關系表,在關系表中用ForeignKey方式支持基於外鍵關系表的ORM連表查詢,同時明確ManyToManyField字段,所以也支持ORM正向方向連表查詢
-- db_constraint=False斷開關聯可以在ForeignKey或ManyToManyField任意一方完成
class Book(models.Model):
name = models.CharField(max_length=20)
# 明確through與through_fields,ManyToManyField才不會自動建立關系表
author = models.ManyToManyField(to='Author', through='Book_Author')
class Author(models.Model):
name = models.CharField(max_length=20)
class Book_Author(models.Model):
book = models.ForeignKey(to="Book", null=True, on_delete=models.SET_NULL, db_constraint=False)
author = models.ForeignKey(to='Author', null=True, on_delete=models.SET_NULL, db_constraint=False)
time = models.DateField()
總結
手動創建第三張表,第三張表的增刪改就采用關系表類名衍生的create|delete|update,就不再擁有add|clear|remove|set(因為關系表擁有自己的字段,這些方法無法直接操作這些字段)
圖書管理系統
待完成
RBAC 基於角色的權限管理
在web領域中,url就是一切
ORM中的事務操作
什么是事務
- 在 MySQL 中只有使用了 Innodb 數據庫引擎的數據庫或表才支持事務。
- 事務處理可以用來維護數據庫的完整性,保證成批的 SQL 語句要么全部執行,要么全部不執行。
- 事務用來管理 insert,update,delete 語句
客戶A要給客戶B轉一筆錢,這個在數據庫中需要進行兩步:
1.客戶A減錢
2.客戶B加錢
如果在第一步結束后,服務器出現異常,停下了,第二步沒有進行,如果數據庫使用了事務操作,真的出現異常的時候,前面的操作會進行回滾。
簡單的說就是:要么全部執行成功,要么一個都不執行
這個回滾的操作就叫做數據庫的原子性操作。
四大特性
ACID
- 原子性
- 事務是最小的單位,不可再分
- 一致性
- 事務要求所有的DML語句操作時,必須保證同時成功或者同時失敗
- 隔離性
- 事務與事務之間是隔離的
- 持久性
- 是事務的保證,事務終結的標志(內存的數據持久到硬盤)
數據庫的三大范式(設計范式)
第一范式(1NF)
表中的列只能含有原子性(不可再分)的值
第二范式(2NF)
- 滿足第一范式
- 沒有部分依賴
- 表必須有一個主鍵
- 沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴主鍵的一部分。
第三范式(3NF)
-
滿足第二范式
-
沒有傳遞依賴
即每個屬性都跟主鍵有直接關系而不是間接關系
django開啟事務
導入
from django.db import transaction
開啟
with transaction.atomic()
在縮進的代碼中書寫數據庫操作
該縮進的所有代碼,都是一個事務
pass
回滾
rollback()
回滾就是回到上一個狀態