2019年12月2日院促,Django終于正式發(fā)布了3.0版本。懷著無比的期待夭织,我們來嘗試一下吧吃环!
Django3.0的新特性,其中最主要的就是加入對ASGI的支持伊滋,實(shí)現(xiàn)全雙工的異步通信碳却。
##?Python?Web框架?Django?高級實(shí)戰(zhàn)編程
視頻分享地址:?[https://study.163.com/course/introduction/1209407824.htm?share=2&shareId=400000000535031](https://study.163.com/course/introduction/1209407824.htm?share=2&shareId=400000000535031)
使用上面的鏈接地址進(jìn)入,聯(lián)系QQ??1064468942?可獲得?部分?學(xué)費(fèi)退還?喔,?實(shí)際支出?將少于?所標(biāo)識的價(jià)格
Django高級實(shí)戰(zhàn)課程源代碼與資源包
源代碼分為兩部分笑旺,兩個網(wǎng)站的源代碼都是按照開發(fā)進(jìn)度按章保存的:
新聞博客問答聊天網(wǎng)站的源代碼:?
鏈接:https://pan.baidu.com/s/1cd7HU46ovf_N6foIYpueFA?
最終部署版本?鏈接:https://pan.baidu.com/s/1lFjwT-ygYynHvEgUufWUEQ?
樂乎在線閱讀網(wǎng)的源代碼:?
鏈接:https://pan.baidu.com/s/10WbOVte0PMiIStQEQC4nVQ
網(wǎng)盤提取碼請查看相關(guān)視頻
##?創(chuàng)建Django3工程
利用Pycharm的方便昼浦,直接通過virtualenv創(chuàng)建虛擬環(huán)境,并安裝Django3.0筒主。
打開控制臺关噪,看看都安裝了哪些庫:
```bash
(venv)?D:\work\for_test\django3>pip?list
Package????Version
------
asgiref????3.2.3
Django?????3.0
pip????????10.0.1
pytz???????2019.3
setuptools?39.1.0
sqlparse???0.3.0
```
除了pytz和sqlparse,又自動安裝了asgiref乌妙。
asigref由Django軟件基金會開發(fā)和維護(hù)使兔,是一個Django生態(tài)中的庫。
先啟動一下服務(wù)器藤韵,看看Django是否正常運(yùn)行:
可以看到虐沥,運(yùn)行沒問題!
##?學(xué)習(xí)官方文檔
畢竟是新特性泽艘,先到官網(wǎng)看看文檔怎么寫的欲险。
如下所示:
主要內(nèi)容是關(guān)于ASGI服務(wù)如何部署的,如下所示:
```
How?to?deploy?with?ASGI
As?well?as?WSGI,?Django?also?supports?deploying?on?ASGI,?the?emerging?Python?standard?for?asynchronous?web?servers?and?applications.
Django’s?startproject?management?command?sets?up?a?default?ASGI?configuration?for?you,?which?you?can?tweak?as?needed?for?your?project,?and?direct?any?ASGI-compliant?application?server?to?use.
Django?includes?getting-started?documentation?for?the?following?ASGI?servers:
How?to?use?Django?with?Daphne
How?to?use?Django?with?Uvicorn
The?application?object
Like?WSGI,?ASGI?has?you?supply?an?application?callable?which?the?application?server?uses?to?communicate?with?your?code.?It’s?commonly?provided?as?an?object?named?application?in?a?Python?module?accessible?to?the?server.
The?startproject?command?creates?a?file?<project_name>/asgi.py?that?contains?such?an?application?callable.
It’s?not?used?by?the?development?server?(runserver),?but?can?be?used?by?any?ASGI?server?either?in?development?or?in?production.
ASGI?servers?usually?take?the?path?to?the?application?callable?as?a?string;?for?most?Django?projects,?this?will?look?like?myproject.asgi:application.
Warning
While?Django’s?default?ASGI?handler?will?run?all?your?code?in?a?synchronous?thread,?if?you?choose?to?run?your?own?async?handler?you?must?be?aware?of?async-safety.
Do?not?call?blocking?synchronous?functions?or?libraries?in?any?async?code.?Django?prevents?you?from?doing?this?with?the?parts?of?Django?that?are?not?async-safe,?but?the?same?may?not?be?true?of?third-party?apps?or?Python?libraries.
Configuring?the?settings?module
When?the?ASGI?server?loads?your?application,?Django?needs?to?import?the?settings?module?—?that’s?where?your?entire?application?is?defined.
Django?uses?the?DJANGO_SETTINGS_MODULE?environment?variable?to?locate?the?appropriate?settings?module.?It?must?contain?the?dotted?path?to?the?settings?module.?You?can?use?a?different?value?for?development?and?production;?it?all?depends?on?how?you?organize?your?settings.
If?this?variable?isn’t?set,?the?default?asgi.py?sets?it?to?mysite.settings,?where?mysite?is?the?name?of?your?project.
Applying?ASGI?middleware
To?apply?ASGI?middleware,?or?to?embed?Django?in?another?ASGI?application,?you?can?wrap?Django’s?application?object?in?the?asgi.py?file.?For?example:
from?some_asgi_library?import?AmazingMiddleware
application?=?AmazingMiddleware(application)
```
全文的意思是匹涮,你需要安裝Daphne天试,然后調(diào)用Django的application來啟動ASGI服務(wù)器∪坏停總結(jié)就以下幾點(diǎn):
?-?不能用?`python?manage.py?runserver`?的方式啟動ASGI服務(wù)器喜每,這只會啟動傳統(tǒng)的、默認(rèn)的WSGI服務(wù)器脚翘,也就是老版本的東西
?-?要啟動ASGI服務(wù)器灼卢,你需要使用Daphne或者Uvicorn。推薦使用Daphne来农,這是Django軟件基金會開發(fā)的一個基于ASGI?(HTTP/WebSocket)的服務(wù)器鞋真。
?-?有一個?`myproject.asgi:application`?文件,是ASGI通信的接口沃于,Django默認(rèn)自帶
????你可以配置?`DJANGO_SETTINGS_MODULE`?環(huán)境涩咖,或者使用默認(rèn)的?`your_project.settings`
??-?可以使用第三方ASGI中間件
我們看看Daphne海诲,點(diǎn)擊Django給的連接,跳轉(zhuǎn)到相關(guān)頁面檩互,內(nèi)容如下:
```
How?to?use?Django?with?Daphne
Daphne?is?a?pure-Python?ASGI?server?for?UNIX,?maintained?by?members?of?the?Django?project.?It?acts?as?the?reference?server?for?ASGI.
Installing?Daphne
You?can?install?Daphne?with?pip:
python?-m?pip?install?daphne
Running?Django?in?Daphne
When?Daphne?is?installed,?a?daphne?command?is?available?which?starts?the?Daphne?server?process.?At?its?simplest,?Daphne?needs?to?be?called?with?the?location?of?a?module?containing?an?ASGI?application?object,?followed?by?what?the?application?is?called?(separated?by?a?colon).
For?a?typical?Django?project,?invoking?Daphne?would?look?like:
daphne?myproject.asgi:application
This?will?start?one?process?listening?on?127.0.0.1:8000.?It?requires?that?your?project?be?on?the?Python?path;?to?ensure?that?run?this?command?from?the?same?directory?as?your?manage.py?file.
```
上述文檔的主要操作步驟如下:
-?`pip?install?daphne`
-?執(zhí)行??`daphne?myproject.asgi:application`?命令特幔,啟動ASGI服務(wù)器
-?瀏覽器訪問?`127.0.0.1:8000`
按照上面的步驟操作,結(jié)果如下:
##?啟動ASGI服務(wù)器
通過?`pip?install?daphne`?即可安裝最新版本的daphne:
```
Collecting?pycparser?(from?cffi!=1.11.3,>=1.8->cryptography>=2.7->autobahn>=0.18->daphne)
Installing?collected?packages:?idna,?hyperlink,?zope.interface,?attrs,?six,?Automat,?constantly,?PyHamcrest,?incremental,?pycparser,?cffi,?cry
ptography,?pyopenssl,?pyasn1,?pyasn1-modules,?service-identity,?twisted,?txaio,?autobahn,?daphne
Successfully?installed?Automat-0.8.0?PyHamcrest-1.9.0?attrs-19.3.0?autobahn-19.11.1?cffi-1.13.2?constantly-15.1.0?cryptography-2.8?daphne-2.4.
0?hyperlink-19.0.0?idna-2.8?incremental-17.5.0?pyasn1-0.4.8?pyasn1-modules-0.2.7?pycparser-2.19?pyopenssl-19.1.0?service-identity-18.1.0?six-1
.13.0?twisted-19.10.0?txaio-18.8.1?zope.interface-4.7.1
```
為了安裝daphne闸昨,需要額外安裝這么多依賴包蚯斯!我們再pip?list看一下:
```bash
(venv)?D:\work\for_test\django3>pip?list
Package??????????Version
----------------?-------
asgiref??????????3.2.3
attrs????????????19.3.0
autobahn?????????19.11.1
Automat??????????0.8.0
cffi?????????????1.13.2
constantly???????15.1.0
cryptography?????2.8
daphne???????????2.4.0
Django???????????3.0
hyperlink????????19.0.0
idna?????????????2.8
incremental??????17.5.0
pip??????????????10.0.1
pyasn1???????????0.4.8
pyasn1-modules???0.2.7
pycparser????????2.19
PyHamcrest???????1.9.0
pyOpenSSL????????19.1.0
pytz?????????????2019.3
service-identity?18.1.0
setuptools???????39.1.0
six??????????????1.13.0
sqlparse?????????0.3.0
Twisted??????????19.10.0
txaio????????????18.8.1
zope.interface???4.7.1
```
安裝成功后,我們會獲得一個`daphne`可執(zhí)行命令饵较,下面我們來啟動服務(wù)器吧拍嵌。
執(zhí)行`daphne?django3.asgi:application`命令,控制臺輸出結(jié)果如下:(將其中的`django3`換成你的工程名字,在`manage.py`文件所在的路徑下執(zhí)行)
```bash
(venv)?D:\work\for_test\django3>daphne?django3.asgi:application
2019-12-04?10:20:07,637?INFO?????Starting?server?at?tcp:port=8000:interface=127.0.0.1
2019-12-04?10:20:07,637?INFO?????HTTP/2?support?not?enabled?(install?the?http2?and?tls?Twisted?extras)
2019-12-04?10:20:07,637?INFO?????Configuring?endpoint?tcp:port=8000:interface=127.0.0.1
2019-12-04?10:20:07,637?INFO?????Listening?on?TCP?address?127.0.0.1:8000
```
當(dāng)然循诉,我們也是可以指定ip和port等參數(shù)的横辆,詳細(xì)請學(xué)習(xí)daphne文檔?`https://pypi.org/project/daphne/`
讀一下啟動信息:
-?默認(rèn)啟動地址是127.0.0.1:8000
-?沒有開啟HTTP/2的支持(需要安裝額外的包)
-?配置了端點(diǎn),開始監(jiān)聽端口
通過瀏覽器來訪問一下吧茄猫!
依然是熟悉的白底火箭圖狈蚤,看起來沒問題。
可是划纽,這是基于HTTP的同步通信脆侮,還不是異步請求!讓我們嘗試一下websocket吧阿浓!
##?嘗試Websocket
瀏覽器中按`F12`進(jìn)入`console`控制臺他嚷,嘗試發(fā)送一個`Websocket`請求:
忽視前面的css問題,重點(diǎn)在于這個ws請求芭毙,居然無法建立連接!返回狀態(tài)碼500卸耘,也就是服務(wù)器錯誤退敦!
再看看Pycharm后臺的信息:
```bash
127.0.0.1:5991?-?-?[04/Dec/2019:10:30:05]?"WSCONNECTING?/"?-?-
2019-12-04?10:30:05,246?ERROR????Exception?inside?application:?Django?can?only?handle?ASGI/HTTP?connections,?not?websocket.
??File?"d:\work\for_test\django3\venv\lib\site-packages\daphne\cli.py",?line?30,?in?asgi
????await?self.app(scope,?receive,?send)
??File?"d:\work\for_test\django3\venv\lib\site-packages\django\core\handlers\asgi.py",?line?146,?in?__call__
????%?scope['type']
??Django?can?only?handle?ASGI/HTTP?connections,?not?websocket.
127.0.0.1:5991?-?-?[04/Dec/2019:10:30:05]?"WSDISCONNECT?/"?-?-
```
重點(diǎn)在這句?``Django?can?only?handle?ASGI/HTTP?connections,?not?websocket.``
什么?Django不支持Websocket蚣抗?說好的ASGI侈百,說好的全雙工異步通信呢?
難道是我哪里搞錯了翰铡?不行钝域,我得看看源碼去!
##?Django3.0的源碼
一路點(diǎn)點(diǎn)點(diǎn)锭魔,翻了個遍例证,發(fā)現(xiàn)Django3.0與之前的2.2關(guān)于ASGI的區(qū)別就是多了下面兩個文件:

`django.core.asgi`很簡單,一看就懂迷捧,如下所是:
```python
import?django
from?django.core.handlers.asgi?import?ASGIHandler
def?get_asgi_application():
????django.setup(set_prefix=False)
????return?ASGIHandler()
```
關(guān)鍵是`django.core.handlers.asgi`這個文件织咧,不到300行胀葱,總共就2個類,代碼就不貼了:
-?ASGIRequest:繼承了HttpRequest類笙蒙,一看就知道是構(gòu)造請求對象
-?ASGIHandler:繼承了base.BaseHandler抵屿,這個就類似WSGIHandler,用于具體處理ASGI請求
讓我們看看它的其中一段代碼:
```python
#?Serve?only?HTTP?connections.
#?FIXME:?Allow?to?override?this.
if?scope['type']?!=?'http':
????raise?ValueError(
????????'Django?can?only?handle?ASGI/HTTP?connections,?not?%s.'
????????%?scope['type']
????)
```
這就是我們前面在瀏覽器中發(fā)送ws請求捅位,但是無法建立連接的原因轧葛!
如果`scope`的`type`屬性不是`http`,那么彈出`ValueError`異常艇搀,并提示不支持該類連接朝群!
再看看人家寫的注釋,明明白白的寫著`Serve?only?HTTP?connections.?FIXME:?Allow?to?override?this.`中符。翻譯過來就是只支持HTTP連接姜胖,請自己重寫這部分內(nèi)容修復(fù)這個缺陷。FIXME淀散!FIXME右莱!
##?總結(jié)
與Django3.0關(guān)于異步通信的初體驗(yàn)很不好,Django真的目前只提供了個接口档插,內(nèi)部實(shí)現(xiàn)還沒做
由于相關(guān)資料太少慢蜓,多方查找,據(jù)說:
????Django會在后續(xù)的版本陸續(xù)實(shí)現(xiàn)完整的原生的異步通信能力郭膛,從同步機(jī)制切換到可兼容的異步機(jī)制
????目前3.0階段晨抡,要與websocket通信依然得通過`django-channel`庫,還不是原生支持