Django3.0 初體驗

此前博主曾經寫過一篇博文,介紹了Django3.0的新特性,其中最主要的就是加入對ASGI的支持,實現全雙工的異步通訊。
(更多Django的教程和博客,能夠訪問個人官網http://www.liujiangblog.com,或者收藏個人微信公衆號‘Django之家’。)css

2019年12月2日,Django終於正式發佈了3.0版本。懷着無比的期待,咱們來嘗試一下吧!html

(附ASGI官方文檔地址:https://asgi.readthedocs.io/en/latest/extensions.htmlpython

1、建立Django3工程

1575424609514

利用Pycharm的方便,直接經過virtualenv建立虛擬環境,並安裝Django3.0。web

打開控制檯,看看都安裝了哪些庫:sql

(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。django

asigref由Django軟件基金會開發和維護,是一個Django生態中的庫。瀏覽器

先啓動一下服務器,看看Django是否正常運行:服務器

1575424868819

沒毛病,能夠把服務器關了!微信

2、學習官方文檔

畢竟是很是重要和複雜的新特性,先到官網取取經,看看文檔怎麼寫的。websocket

找了一圈,What?就這麼點東西?

1575425030020

先康康吧。
(更多Django的教程和博客,能夠訪問個人官網http://www.liujiangblog.com,或者收藏個人微信公衆號‘Django之家’。)

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)

文檔短小無力,內容稀少!

總結就如下幾點:

  • 不能用python manage.py runserver的方式啓動ASGI服務器,這隻會啓動傳統的、默認的WSGI服務器,也就是老版本的東西
  • 要啓動ASGI服務器,你須要使用Daphne或者Uvicorn。推薦使用Daphne,這是Django軟件基金會開發的一個基於ASGI (HTTP/WebSocket)的服務器。
  • 有一個myproject.asgi:application文件,是ASGI通訊的接口,Django默認自帶
  • 你能夠配置DJANGO_SETTINGS_MODULE 環境,或者使用默認的your_project.settings
  • 可使用第三方ASGI中間件

再簡單粗暴點,全文的意思是,你須要安裝Daphne,而後調用Django的application來啓動ASGI服務器。

好吧,咱們看看Daphne,點擊Django給的鏈接,跳轉到相關頁面,內容更少:

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.

翻譯過來就是:

  1. pip安裝daphne
  2. 執行daphne myproject.asgi:application命令,啓動ASGI服務器
  3. 瀏覽器訪問127.0.0.1:8000

我們照作!

3、啓動ASGI服務器

經過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看一下:

(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可執行命令,下面咱們來啓動服務器吧。

執行daphne django3.asgi:application命令。(將其中的django3換成你的工程名字,在manage.py文件所在的路徑下執行)

(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

固然,咱們也是能夠指定ip和port等參數的,詳細請學習daphne文檔https://pypi.org/project/daphne/

讀一下人家的啓動信息:

  • 默認啓動地址是127.0.0.1:8000
  • 沒有開啓HTTP/2的支持(須要安裝額外的包)
  • 配置了端點,開始監聽端口

Nice,經過瀏覽器來訪問一下吧!

依然是熟悉的白底火箭圖!圖片我就不貼了,看起來沒問題。

但是,這是基於HTTP的同步通訊,還不是異步請求!讓咱們嘗試一下websocket吧!

4、嘗試Websocket

瀏覽器中按F12進入‘坦克模式’,再進入console控制檯,嘗試發送一個Websocket請求:

1575426639860

忽視前面的css問題,重點在於這個ws請求,竟然沒法創建鏈接!返回狀態碼500,也就是服務器錯誤!

再看看Pycharm後臺的信息:

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 /" - -

重點在這句Django can only handle ASGI/HTTP connections, not websocket.

什麼?Django不支持Websocket?說好的ASGI,說好的全雙工異步通訊呢?

難道是我哪裏搞錯了?不行,我得看看源碼去!

5、Django3.0源碼

一路點點點,翻了個遍,發現Django3.0與以前的2.2關於ASGI的區別就是多了下面兩個文件:

1575427104722

django.core.asgi很簡單,一看就懂,很少說:

import django
from django.core.handlers.asgi import ASGIHandler

def get_asgi_application():
    django.setup(set_prefix=False)
    return ASGIHandler()

關鍵是django.core.handlers.asgi這個文件,不到300行,總共就2個類,代碼就不貼了:

  • ASGIRequest:繼承了HttpRequest類,一看就知道是構造請求對象
  • ASGIHandler:繼承了base.BaseHandler,這個就相似WSGIHandler,用於具體處理ASGI請求

讓咱們看看它的其中一段代碼:

# 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']
    )

這就是咱們前面在瀏覽器中發送ws請求,可是沒法創建鏈接的緣由!

若是scope的type屬性不是http,那麼彈出ValueError異常,並提示不支持該類鏈接!

再看看人家寫的註釋,明明白白的寫着Serve only HTTP connections. FIXME: Allow to override this.。翻譯過來就是隻支持HTTP鏈接,請本身重寫這部份內容修復這個缺陷。FIXME!FIXME!

好吧,我認可白高興了一場。

6、總結

與Django3.0關於異步通訊的初體驗很很差,有下面幾點猜想:

  1. 可能我水平不行,不會用Django
  2. 可能不是經過Websocket,而是別的手段與ASGI通訊
  3. Django真的目前只提供了個接口,內部實現還沒作

因爲相關資料太少,多方查找,聽說:

  1. Django會在後續的版本陸續實現完整的原生的異步通訊能力,從同步機制切換到可兼容的異步機制
  2. 目前3.0階段,要與websocket通訊依然得經過django-channel庫,還不是原生支持

好了,關於Django3.0的事就說到這裏,更多Django的教程和博客,能夠訪問個人官網http://www.liujiangblog.com,或者收藏個人微信公衆號‘Django之家’。文中內容若是有錯誤,請多批評指正,謝謝!

相關文章
相關標籤/搜索