Django 3.1將於2020年8月發佈!從3.1版本開始,Django將逐步原生支持異步,好比異步視圖和中間件。html
Django 3.1只支持Python 3.六、3.七、3.8以及更高版本。python
下面重點介紹Django3.1的新特性:算法
在Django3.1中,要定義一個異步視圖很簡單,只需使用Python的async def
語法,Django會自動探測到它們,並在異步上下文中運行它們。異步視圖有不少優勢,好比可以在不使用Python線程的狀況下爲數百個鏈接提供服務,容許使用慢速流、長輪詢和其餘的響應類型等等。django
async def my_view(request): await asyncio.sleep(0.5) return HttpResponse('Hello, async world!')
不管你是運行在WSGI仍是ASGI模式,都支持全部異步特性。json
可是,在WSGI模式下使用異步代碼可能會有性能損失,由於此時異步視圖將在它們本身的一次性事件循環中運行,這意味着你雖然可使用異步特性,如並行的異步HTTP請求,但卻沒法得到異步堆棧的好處。緩存
咱們能夠爲所欲爲地混合異步和同步的視圖、中間件和測試,Django會確保咱們始終得到正確的執行上下文。可是,Django官方建議大多數時候依然使用同步視圖,只有在真正有需求時使用異步視圖,不過這徹底取決於你的選擇,你能夠任性的都使用異步視圖。安全
Django3.1版本中的ORM、緩存層和其餘執行長時間網絡調用的代碼還暫時不支持異步訪問,會在後期發佈的版本中增長對它們的支持。(個人官網https://www.liujiangblog.com...。)Django對異步的支持徹底向後兼容,對現有的同步代碼沒有速度限制,它不會對任何現有的Django項目產生明顯的影響。網絡
下面是另一個例子:session
import datetime from django.http import HttpResponse async def current_datetime(request): now = datetime.datetime.now() html = '<html><body><h1>歡迎訪問劉江Django教程:https://www.liujiangblog.com</h1>It is now %s.</body></html>' % now return HttpResponse(html)
由於目前,Django尚未完成異步ORM的功能開發,爲了在異步視圖中使用ORM,須要將同步的代碼轉換爲異步的代碼,這就須要使用asgiref
庫,這個庫已經做爲安裝依賴隨Django一塊兒被安裝。異步
核心是使用asgiref.sync
中的sync_to_async
方法。
使用方法有兩種,第一種以函數調用的方式,注意括號的位置:
from asgiref.sync import sync_to_async results = sync_to_async(Blog.objects.get)(pk=123) #注意圓括號,千萬不要寫成results = sync_to_async(Blog.objects.get(pk=123))
第二種以裝飾器的方式:
from asgiref.sync import sync_to_async @sync_to_async def get_blog(pk): return Blog.objects.select_related('author').get(pk=pk)
對等的,其實也有一個異步變同步的函數,用於在同步視圖中包裝異步調用:
from asgiref.sync import async_to_sync async def get_data(...): ... sync_get_data = async_to_sync(get_data) @async_to_sync async def get_other_data(...): ...
從Django3.1開始,中間件能夠支持同步和異步請求的任何組合。若是Django不能同時支持這二者,它將調整請求以知足中間件的需求,但會下降性能。
默認狀況下,Django假設你的中間件只能處理同步請求。要更改這個假設,請在中間件工廠函數或類上設置如下屬性:
sync_capable
: 一個布爾值,指示中間件是否能夠處理同步請求。默認爲True。async_capable
: 一個布爾值,指示中間件是否能夠處理異步請求。默認爲False。若是中間件同時具備sync_capable=True
和async_capable=True
,那麼Django將在不轉換請求的狀況下傳遞它。在這種狀況下,可使用asyncio.iscoroutine function()
檢查傳遞給您的get_response
對象是不是一個協程函數,從而肯定您的中間件是否會接收異步請求。
記住一個概念:同步和異步能力不是非左即右,互相矛盾的存在,能夠共存!
那麼怎麼將中間件設置爲同步的,或者異步的,或者同步加異步的呢?
在django.utils.decorators
模塊中包含sync_only_middleware
、async_only_middleware
和sync_and_async_middleware
三個裝飾器,用於幫咱們實現上面的功能。
中間件返回的可調用函數必須與get_response
方法的sync或async性質匹配。若是有異步get_response
響應,則必須返回一個協程函數(async def)。
若是中間件提供了process_view
、process_template_response
和process_exception
方法,則還應進行相應的調整以匹配同步/異步模式。若是你不這樣作,Django會根據須要對它們進行單獨的調整,併產生額外的性能懲罰。
下面是一個如何建立同時支持同步和異步功能的中間件的示例:
import asyncio from django.utils.decorators import sync_and_async_middleware @sync_and_async_middleware def simple_middleware(get_response): # One-time configuration and initialization goes here. if asyncio.iscoroutinefunction(get_response): async def middleware(request): # Do something here! response = await get_response(request) return response else: def middleware(request): # Do something here! response = get_response(request) return response return middleware
總的來講,Django對同步/異步視圖和同步/異步中間件之間的搭配組合有很好的適配能力,不會讓咱們的項目運行不起來。只不過若是搭配不當,會致使性能損失。
從Django3.1開始,具有異步測試能力。
若是您只想測試異步視圖的輸出,標準測試客戶端將在本身的異步循環中運行它們,你不須要作任何額外的工做。
可是,若是你想爲Django項目編寫徹底異步的測試,則須要考慮一些事情。
首先,測試方法必須是測試類上的async def
方法(以便爲它們提供異步上下文)。Django將自動檢測任何異步測試幷包裝它們,以便它們在本身的事件循環中運行。
其次,若是要在異步函數中進行測試,還必須使用異步測試客戶端。也就是django.test.AsyncClient
或self.async_client
。
除了不支持follow
參數外,AsyncClient
的使用方法和同步的測試客戶端基本相同,但全部發出請求的方法都必須使用await
語法:
async def test_my_thing(self): response = await self.async_client.get('/some-url/') self.assertEqual(response.status_code, 200)
Django3.1新增了 models.JSONField
和forms.JSONField
兩種新的模型字段類型,用於保存JSON編碼的數據。
MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL和SQLite 3.9.0+都支持JSONField。
JSONField能夠自定義編碼器和解碼器,這從它的定義上就能夠看出來:
class JSONField(encoder=None, decoder=None, **options)
JSONField.encoder
可選參數。用於對諸如datetime.datetime
或者UUID
之類的標準JSON序列化不了的數據指定自定義的編碼器。它必須是json.JSONEncoder
的子類,好比 DjangoJSONEncoder
JSONField.decoder
可選參數。用於解碼咱們自定義的編碼數據。必須是 json.JSONDecoder
的子類。
若是你爲JSONField字段提供了一個default默認值,它的值必須是一個不可變的類型。
對於forms.JSONField
,除了一樣能夠自定義編碼器和解碼器,還有一些表單特有的性質:
Textarea
''
(空字符串)required
, invalid
下面例舉一些相對較小的新功能。其中最主要的是,Django3.1開始使用pathlib.Path
來替代傳統的os.path了,建議你們仍是儘快更新知識,遷移到pathlib.Path
上來
django.contrib.admin
django.contrib.admin.EmptyFieldListFilter
XRegExp
升級到3.2.0django.contrib.auth
PASSWORD_RESET_TIMEOUT
配置項,用於替代4.0中將廢棄的 PASSWORD_RESET_TIMEOUT_DAYS
AbstractBaseUser.get_session_auth_hash()
將使用SHA-256哈希算法django.contrib.humanize
intword
將支持負整數django.contrib.sessions
SESSION_COOKIE_SAMESITE
如今能夠接收 'None'
(字符串)django.contrib.staticfiles
STATICFILES_DIRS
設置項開始支持 pathlib.Path
FileSystemStorage.save()
方法支持 pathlib.Path
FileField
和ImageField
如今支持可調用的參數用於保存數據。這讓你能在運行時動態選擇不一樣的存儲位置。__init__.py
文件的目錄中加載了PositiveBigIntegerField
字段類型,相似 PositiveIntegerField
,從 0
到9223372036854775807
都是安全的。on_delete
參數,如今能夠接收一個RESTRICT
值,用於模擬SQL語言中的 ON DELETE RESTRICT
約束行爲。