Django3.0 异步通信初体验(小结)
此前博主曾经写过一篇博文,介绍了Django3.0的新特性,其中最主要的就是加入对ASGI的支持,实现全双工的异步通信。
2019年12月2日,Django终于正式发布了3.0版本。怀着无比的期待,我们来尝试一下吧!
(附ASGI官方文档地址:https://asgi.readthedocs.io/en/latest/extensions.html)
一、创建Django3工程
利用Pycharm的方便,直接通过virtualenv创建虚拟环境,并安装Django3.0。
打开控制台,看看都安装了哪些库:
(venv)D:\work\for_test\django3>piplist PackageVersion ------ asgiref3.2.3 Django3.0 pip10.0.1 pytz2019.3 setuptools39.1.0 sqlparse0.3.0
除了pytz和sqlparse,又自动安装了asgiref。
asigref由Django软件基金会开发和维护,是一个Django生态中的库。
先启动一下服务器,看看Django是否正常运行:
没毛病,可以把服务器关了!
二、学习官方文档
毕竟是非常重要和复杂的新特性,先到官网取取经,看看文档怎么写的。
找了一圈,What?就这么点东西?
先康康吧。
HowtodeploywithASGI AswellasWSGI,DjangoalsosupportsdeployingonASGI,theemergingPythonstandardforasynchronouswebserversandapplications. Django'sstartprojectmanagementcommandsetsupadefaultASGIconfigurationforyou,whichyoucantweakasneededforyourproject,anddirectanyASGI-compliantapplicationservertouse. Djangoincludesgetting-starteddocumentationforthefollowingASGIservers: HowtouseDjangowithDaphne HowtouseDjangowithUvicorn Theapplicationobject LikeWSGI,ASGIhasyousupplyanapplicationcallablewhichtheapplicationserverusestocommunicatewithyourcode.It'scommonlyprovidedasanobjectnamedapplicationinaPythonmoduleaccessibletotheserver. Thestartprojectcommandcreatesafile/asgi.pythatcontainssuchanapplicationcallable. It'snotusedbythedevelopmentserver(runserver),butcanbeusedbyanyASGIservereitherindevelopmentorinproduction. ASGIserversusuallytakethepathtotheapplicationcallableasastring;formostDjangoprojects,thiswilllooklikemyproject.asgi:application. Warning WhileDjango'sdefaultASGIhandlerwillrunallyourcodeinasynchronousthread,ifyouchoosetorunyourownasynchandleryoumustbeawareofasync-safety. Donotcallblockingsynchronousfunctionsorlibrariesinanyasynccode.DjangopreventsyoufromdoingthiswiththepartsofDjangothatarenotasync-safe,butthesamemaynotbetrueofthird-partyappsorPythonlibraries. Configuringthesettingsmodule WhentheASGIserverloadsyourapplication,Djangoneedstoimportthesettingsmodule—that'swhereyourentireapplicationisdefined. DjangousestheDJANGO_SETTINGS_MODULEenvironmentvariabletolocatetheappropriatesettingsmodule.Itmustcontainthedottedpathtothesettingsmodule.Youcanuseadifferentvaluefordevelopmentandproduction;italldependsonhowyouorganizeyoursettings. Ifthisvariableisn'tset,thedefaultasgi.pysetsittomysite.settings,wheremysiteisthenameofyourproject. ApplyingASGImiddleware ToapplyASGImiddleware,ortoembedDjangoinanotherASGIapplication,youcanwrapDjango'sapplicationobjectintheasgi.pyfile.Forexample: fromsome_asgi_libraryimportAmazingMiddleware application=AmazingMiddleware(application)
文档短小无力,内容稀少!
总结就以下几点:
- 不能用pythonmanage.pyrunserver的方式启动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给的连接,跳转到相关页面,内容更少:
HowtouseDjangowithDaphne Daphneisapure-PythonASGIserverforUNIX,maintainedbymembersoftheDjangoproject.ItactsasthereferenceserverforASGI. InstallingDaphne YoucaninstallDaphnewithpip: python-mpipinstalldaphne RunningDjangoinDaphne WhenDaphneisinstalled,adaphnecommandisavailablewhichstartstheDaphneserverprocess.Atitssimplest,DaphneneedstobecalledwiththelocationofamodulecontaininganASGIapplicationobject,followedbywhattheapplicationiscalled(separatedbyacolon). ForatypicalDjangoproject,invokingDaphnewouldlooklike: daphnemyproject.asgi:application Thiswillstartoneprocesslisteningon127.0.0.1:8000.ItrequiresthatyourprojectbeonthePythonpath;toensurethatrunthiscommandfromthesamedirectoryasyourmanage.pyfile.
翻译过来就是:
- pip安装daphne
- 执行daphnemyproject.asgi:application命令,启动ASGI服务器
- 浏览器访问127.0.0.1:8000
咱们照做!
三、启动ASGI服务器
通过pipinstalldaphne即可安装最新版本的daphne:
Collectingpycparser(fromcffi!=1.11.3,>=1.8->cryptography>=2.7->autobahn>=0.18->daphne) Installingcollectedpackages:idna,hyperlink,zope.interface,attrs,six,Automat,constantly,PyHamcrest,incremental,pycparser,cffi,cry ptography,pyopenssl,pyasn1,pyasn1-modules,service-identity,twisted,txaio,autobahn,daphne SuccessfullyinstalledAutomat-0.8.0PyHamcrest-1.9.0attrs-19.3.0autobahn-19.11.1cffi-1.13.2constantly-15.1.0cryptography-2.8daphne-2.4. 0hyperlink-19.0.0idna-2.8incremental-17.5.0pyasn1-0.4.8pyasn1-modules-0.2.7pycparser-2.19pyopenssl-19.1.0service-identity-18.1.0six-1 .13.0twisted-19.10.0txaio-18.8.1zope.interface-4.7.1
为了安装daphne,需要额外安装这么多依赖包!我们再piplist看一下:
(venv)D:\work\for_test\django3>piplist PackageVersion ----------------------- asgiref3.2.3 attrs19.3.0 autobahn19.11.1 Automat0.8.0 cffi1.13.2 constantly15.1.0 cryptography2.8 daphne2.4.0 Django3.0 hyperlink19.0.0 idna2.8 incremental17.5.0 pip10.0.1 pyasn10.4.8 pyasn1-modules0.2.7 pycparser2.19 PyHamcrest1.9.0 pyOpenSSL19.1.0 pytz2019.3 service-identity18.1.0 setuptools39.1.0 six1.13.0 sqlparse0.3.0 Twisted19.10.0 txaio18.8.1 zope.interface4.7.1
不管了,就当没看见。
安装成功后,我们会获得一个daphne可执行命令,下面我们来启动服务器吧。
执行daphnedjango3.asgi:application命令。(将其中的django3换成你的工程名字,在manage.py文件所在的路径下执行)
(venv)D:\work\for_test\django3>daphnedjango3.asgi:application 2019-12-0410:20:07,637INFOStartingserverattcp:port=8000:interface=127.0.0.1 2019-12-0410:20:07,637INFOHTTP/2supportnotenabled(installthehttp2andtlsTwistedextras) 2019-12-0410:20:07,637INFOConfiguringendpointtcp:port=8000:interface=127.0.0.1 2019-12-0410:20:07,637INFOListeningonTCPaddress127.0.0.1:8000
当然,我们也是可以指定ip和port等参数的,详细请学习daphne文档https://pypi.org/project/daphne/
读一下人家的启动信息:
- 默认启动地址是127.0.0.1:8000
- 没有开启HTTP/2的支持(需要安装额外的包)
- 配置了端点,开始监听端口
Nice,通过浏览器来访问一下吧!
依然是熟悉的白底火箭图!图片我就不贴了,看起来没问题。
可是,这是基于HTTP的同步通信,还不是异步请求!让我们尝试一下websocket吧!
四、尝试Websocket
浏览器中按F12进入‘坦克模式',再进入console控制台,尝试发送一个Websocket请求:
忽视前面的css问题,重点在于这个ws请求,居然无法建立连接!返回状态码500,也就是服务器错误!
再看看Pycharm后台的信息:
127.0.0.1:5991--[04/Dec/2019:10:30:05]"WSCONNECTING/"-- 2019-12-0410:30:05,246ERRORExceptioninsideapplication:DjangocanonlyhandleASGI/HTTPconnections,notwebsocket. File"d:\work\for_test\django3\venv\lib\site-packages\daphne\cli.py",line30,inasgi awaitself.app(scope,receive,send) File"d:\work\for_test\django3\venv\lib\site-packages\django\core\handlers\asgi.py",line146,in__call__ %scope['type'] DjangocanonlyhandleASGI/HTTPconnections,notwebsocket. 127.0.0.1:5991--[04/Dec/2019:10:30:05]"WSDISCONNECT/"--
重点在这句DjangocanonlyhandleASGI/HTTPconnections,notwebsocket.
什么?Django不支持Websocket?说好的ASGI,说好的全双工异步通信呢?
难道是我哪里搞错了?不行,我得看看源码去!
五、Django3.0源码
一路点点点,翻了个遍,发现Django3.0与之前的2.2关于ASGI的区别就是多了下面两个文件:
django.core.asgi很简单,一看就懂,不多说:
importdjango fromdjango.core.handlers.asgiimportASGIHandler defget_asgi_application(): django.setup(set_prefix=False) returnASGIHandler()
关键是django.core.handlers.asgi这个文件,不到300行,总共就2个类,代码就不贴了:
- ASGIRequest:继承了HttpRequest类,一看就知道是构造请求对象
- ASGIHandler:继承了base.BaseHandler,这个就类似WSGIHandler,用于具体处理ASGI请求
让我们看看它的其中一段代码:
#ServeonlyHTTPconnections. #FIXME:Allowtooverridethis. ifscope['type']!='http': raiseValueError( 'DjangocanonlyhandleASGI/HTTPconnections,not%s.' %scope['type'] )
这就是我们前面在浏览器中发送ws请求,但是无法建立连接的原因!
如果scope的type属性不是http,那么弹出ValueError异常,并提示不支持该类连接!
再看看人家写的注释,明明白白的写着ServeonlyHTTPconnections.FIXME:Allowtooverridethis.。翻译过来就是只支持HTTP连接,请自己重写这部分内容修复这个缺陷。FIXME!FIXME!
好吧,我承认白高兴了一场。
六、总结
与Django3.0关于异步通信的初体验很不好,有下面几点猜测:
- 可能我水平不行,不会用Django
- 可能不是通过Websocket,而是别的手段与ASGI通信
- Django真的目前只提供了个接口,内部实现还没做
由于相关资料太少,多方查找,据说:
- Django会在后续的版本陆续实现完整的原生的异步通信能力,从同步机制切换到可兼容的异步机制
- 目前3.0阶段,要与websocket通信依然得通过django-channel库,还不是原生支持
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。