最主要feature:Model Conatrains
可以在 model 的 Meta 中定義一個 constrains 列表。比如下面這個例子,新增了一個age
欄位資料必須大於等於18的限制。
注意:不能在 AbstractModel 類裡面定義constrains,因為每個 constrain都必須要有一個唯一的名字。如果在AbstractModel中定義的話,勢必會重複。
from django.db import models
class Customer(models.Model):
age = models.IntegerField()
class Meta:
constraints = [
models.CheckConstraint(check=models.Q(age__gte=18), name='age_gte_18'),
]
複製程式碼
知識點回顧:models.Q 查詢
models.Q 可以用來組合產生複雜的查詢語句,比如 OR 查詢:
queryset = User.objects.filter(
Q(first_name__startswith='R') | Q(last_name__startswith='D')
)
複製程式碼
AND 查詢:
queryset = User.objects.filter(
Q(first_name__startswith='R') & Q(last_name__startswith='D')
)
複製程式碼
first_name
以‘R’
開頭, 但是 last_name
不以Z
開頭:
queryset = User.objects.filter(
Q(first_name__startswith='R') & ~Q(last_name__startswith='Z')
)
複製程式碼
詳情情見:
class CheckConstraint
check
必填引數。
需要傳入一個Q
物件,表明你需要怎樣的 constrain 要求,比如CheckConstraint(check=Q(age__gte=18), name='age_gte_18')
確保age
欄位用於不會小於18.
name
必填引數。必須是唯一的。
class UniqueConstraint
fields
對哪些 fields 做唯一限制。比如UniqueConstraint(fields=['room', 'date'], name='unique_booking')
確保每個 room 一天只能被預訂一次。
name
同上,必須是唯一的。
condition
滿足什麼條件時才要求強制 constrain 條件。
測試用例:
model 相關
automatic transaction的變化
2.2釋出日誌裡面一個不起眼的地方寫了這樣一句:
Django no longer always starts a transaction when a single query is being performed, such as Model.save(), QuerySet.update(), and Model.delete(). This improves the performance of autocommit by reducing the number of database round trips.
也就是說 django 不再和之前一樣,每個 query(比如 save,update,delete) 都會開啟一個 transaction。這樣可以通過減少 django <-> 資料庫往返次數來提高效率。
Index.condition
考慮到這樣的應用場景:table 很大,但是 query 只會查詢一小部分的資料。為所有資料項都建一個索引是沒必要的,這時候就可以針對某一部分特定資料建立索引。
比如下面這個例子:
indexes = [
models.Index(
fields=['username'],
condition=models.Q(age__gte=30),
name='idx_username_age_gte30'
)
]
複製程式碼
將只會為年齡大於30歲的使用者在username
這個欄位上建立索引。
Index.condition 底層支援依賴於資料庫的partial indexes。 而MySQL、MariaDB、Oracle都不支援partial indexes,所以這些資料庫會直接忽略掉。
bulk_create
增加了一個ignore_conflicts
引數,設定為 TRUE 的時候告訴資料庫忽略由於 constrain 產生的錯誤。
bulk_update
bulk_update(objs, fields, batch_size=None)
需要 update 大量資料的時候很有用。
>>> objs = [
... Entry.objects.create(headline='Entry 1'),
... Entry.objects.create(headline='Entry 2'),
... ]
>>> objs[0].headline = 'This is entry 1'
>>> objs[1].headline = 'This is entry 2'
>>> Entry.objects.bulk_update(objs, ['headline'])
複製程式碼
這樣會比使用一個 for 迴圈一個一個呼叫update()
方法速度更快。
有幾點需要注意:
save()
方法不會被呼叫,所以post_save
和pre_save
訊號將不會觸發。- 如果資料量很大,可以指定
batch_szie 引數
migrations
新增了一個--plan
命令列引數,用來檢視 django 將要執行什麼資料庫修改操作。
針對 PG 資料庫的優化
django.contrib.postgres
ordering
引數增加了ArrayAgg
和StringAgg
。可以針對 aggv 資料來做排序。- 新增的
BTreeIndex
,HashIndex
和SpGistIndex
類允許建立 B-Tree, hash, and SP-GiST 索引。 BrinIndex
現在有了一個autosummarize
引數。SearchQuery
的search_type
做了些變化。
HttpRequest
新增了HttpRequest.headers
,以便更方便地獲取請求頭資訊。
>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}
>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True
>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
複製程式碼
之前需要通過 request.META獲取,相對要麻煩了很多。在2.2之前的版本,如果你想要獲取所有的 HTTP 請求頭的話,可以這麼獲取:
import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value)
in request.META.items() if header.startswith('HTTP_'))
複製程式碼
其他特性
其他瑣碎的東西還有很多,比如:
collectstatic --ignore PATTERN
選項,忽略指定模式的靜態資源。inspectdb
有了更豐富的功能。Tests
新功能。
詳細的,還是去看官方的文件吧。此外還提到了一些往前不相容的改變,如果你的專案裡面用到了,也需要注意注意。
我的公眾號:全棧不存在的