Django3.1異步視圖搶先看

Django 3.1將於2020年8月發佈!從3.1版本開始,Django將逐步原生支持異步,好比異步視圖和中間件。html

Django 3.1只支持Python 3.六、3.七、3.8以及更高版本。python

下面重點介紹Django3.1的新特性:算法

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(...):
    ...

2. 異步中間件

從Django3.1開始,中間件能夠支持同步和異步請求的任何組合。若是Django不能同時支持這二者,它將調整請求以知足中間件的需求,但會下降性能。

默認狀況下,Django假設你的中間件只能處理同步請求。要更改這個假設,請在中間件工廠函數或類上設置如下屬性:

  • sync_capable: 一個布爾值,指示中間件是否能夠處理同步請求。默認爲True。
  • async_capable: 一個布爾值,指示中間件是否能夠處理異步請求。默認爲False。

若是中間件同時具備sync_capable=Trueasync_capable=True,那麼Django將在不轉換請求的狀況下傳遞它。在這種狀況下,可使用asyncio.iscoroutine function()檢查傳遞給您的get_response對象是不是一個協程函數,從而肯定您的中間件是否會接收異步請求。

記住一個概念:同步和異步能力不是非左即右,互相矛盾的存在,能夠共存!

那麼怎麼將中間件設置爲同步的,或者異步的,或者同步加異步的呢?

django.utils.decorators模塊中包含sync_only_middlewareasync_only_middlewaresync_and_async_middleware三個裝飾器,用於幫咱們實現上面的功能。

中間件返回的可調用函數必須與get_response方法的sync或async性質匹配。若是有異步get_response響應,則必須返回一個協程函數(async def)。

若是中間件提供了process_viewprocess_template_responseprocess_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對同步/異步視圖和同步/異步中間件之間的搭配組合有很好的適配能力,不會讓咱們的項目運行不起來。只不過若是搭配不當,會致使性能損失。

3. 異步測試

從Django3.1開始,具有異步測試能力。

若是您只想測試異步視圖的輸出,標準測試客戶端將在本身的異步循環中運行它們,你不須要作任何額外的工做。

可是,若是你想爲Django項目編寫徹底異步的測試,則須要考慮一些事情。

首先,測試方法必須是測試類上的async def方法(以便爲它們提供異步上下文)。Django將自動檢測任何異步測試幷包裝它們,以便它們在本身的事件循環中運行。

其次,若是要在異步函數中進行測試,還必須使用異步測試客戶端。也就是django.test.AsyncClientself.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)

4. 新增JSONField

Django3.1新增了 models.JSONFieldforms.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,除了一樣能夠自定義編碼器和解碼器,還有一些表單特有的性質:

  • 默認渲染的HTML元素: Textarea
  • 空值: '' (空字符串)
  • 錯誤信息的鍵: required, invalid

5. 小功能

下面例舉一些相對較小的新功能。其中最主要的是,Django3.1開始使用pathlib.Path來替代傳統的os.path了,建議你們仍是儘快更新知識,遷移到pathlib.Path上來

django.contrib.admin

  • 新的空值過濾功能 django.contrib.admin.EmptyFieldListFilter
  • 能夠清除全部的過濾操做
  • 新增可摺疊的左側邊導航欄,方便咱們進行菜單跳轉
  • XRegExp 升級到3.2.0
  • jQuery升級到3.5.1
  • Select2 升級到4.0.13.

django.contrib.auth

  • PBKDF2密碼哈希的迭代次數從180,000 提升到216,000
  • 新增PASSWORD_RESET_TIMEOUT 配置項,用於替代4.0中將廢棄的 PASSWORD_RESET_TIMEOUT_DAYS
  • 密碼重置將使用 SHA-256哈希算法
  • 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

File Storage

  • FileSystemStorage.save() 方法支持 pathlib.Path
  • FileFieldImageField 如今支持可調用的參數用於保存數據。這讓你能在運行時動態選擇不一樣的存儲位置。

Migrations

  • Migrations如今也能夠從沒有 __init__.py 文件的目錄中加載了

Models

  • 新增PositiveBigIntegerField 字段類型,相似 PositiveIntegerField ,從 09223372036854775807 都是安全的。
  • 對於外鍵和一對一字段的on_delete參數,如今能夠接收一個RESTRICT 值,用於模擬SQL語言中的 ON DELETE RESTRICT約束行爲。

更多特性請參考官方文檔

更多技術文章請訪問: https://www.liujiangblog.com

更多視頻教程請訪問: https://www.liujiangblog.com/video/

相關文章
相關標籤/搜索