Django3.x 初体验

2019年12月2日,Django终于正式发布了3.0版本。怀着无比的期待,我们来尝试一下吧!

Django3.0的新特性,其中最主要的就是加入对ASGI的支持,实现全双工的异步通信。

## Python Web框架 Django 高级实战编程

视频分享地址: [https://study.163.com/course/introduction/1209407824.htm?share=2&shareId=400000000535031](https://study.163.com/course/introduction/1209407824.htm?share=2&shareId=400000000535031)

使用上面的链接地址进入,联系QQ  1064468942 可获得 部分 学费退还 喔, 实际支出 将少于 所标识的价格

Django高级实战课程源代码与资源包

源代码分为两部分,两个网站的源代码都是按照开发进度按章保存的:

新闻博客问答聊天网站的源代码: 

链接:https://pan.baidu.com/s/1cd7HU46ovf_N6foIYpueFA 

最终部署版本 链接:https://pan.baidu.com/s/1lFjwT-ygYynHvEgUufWUEQ 

乐乎在线阅读网的源代码: 

链接:https://pan.baidu.com/s/10WbOVte0PMiIStQEQC4nVQ

网盘提取码请查看相关视频

## 创建Django3工程

利用Pycharm的方便,直接通过virtualenv创建虚拟环境,并安装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软件基金会开发和维护,是一个Django生态中的库。

先启动一下服务器,看看Django是否正常运行:

![在这里插入图片描述](https://imgconvert.csdnimg.cn/aHR0cHM6Ly93d3cubGl1amlhbmdibG9nLmNvbS9zdGF0aWMvaW1hZ2VzL2Jsb2cvMTU3NTQyNDg2ODgxOS5wbmc?x-oss-process=image/format,png)可以看到,运行没问题!

## 学习官方文档

毕竟是新特性,先到官网看看文档怎么写的。

如下所示:

![在这里插入图片描述](https://imgconvert.csdnimg.cn/aHR0cHM6Ly93d3cubGl1amlhbmdibG9nLmNvbS9zdGF0aWMvaW1hZ2VzL2Jsb2cvMTU3NTQyNTAzMDAyMC5wbmc?x-oss-process=image/format,png)主要内容是关于ASGI服务如何部署的,如下所示:

```

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 /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,然后调用Django的application来启动ASGI服务器。总结就以下几点:

 - 不能用 `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给的连接,跳转到相关页面,内容如下:

```

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`

- 执行  `daphne myproject.asgi:application` 命令,启动ASGI服务器

- 浏览器访问 `127.0.0.1:8000`

按照上面的步骤操作,结果如下:

## 启动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看一下:

```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`可执行命令,下面我们来启动服务器吧。

执行`daphne django3.asgi:application`命令,控制台输出结果如下:(将其中的`django3`换成你的工程名字,在`manage.py`文件所在的路径下执行)

```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

```

当然,我们也是可以指定ip和port等参数的,详细请学习daphne文档 `https://pypi.org/project/daphne/`

读一下启动信息:

- 默认启动地址是127.0.0.1:8000

- 没有开启HTTP/2的支持(需要安装额外的包)

- 配置了端点,开始监听端口

通过浏览器来访问一下吧!

依然是熟悉的白底火箭图,看起来没问题。

可是,这是基于HTTP的同步通信,还不是异步请求!让我们尝试一下websocket吧!

## 尝试Websocket

浏览器中按`F12`进入`console`控制台,尝试发送一个`Websocket`请求:

![在这里插入图片描述](https://imgconvert.csdnimg.cn/aHR0cHM6Ly93d3cubGl1amlhbmdibG9nLmNvbS9zdGF0aWMvaW1hZ2VzL2Jsb2cvMTU3NTQyNjYzOTg2MC5wbmc?x-oss-process=image/format,png)忽视前面的css问题,重点在于这个ws请求,居然无法建立连接!返回状态码500,也就是服务器错误!

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

```

重点在这句 ``Django can only handle ASGI/HTTP connections, not websocket.``

什么?Django不支持Websocket?说好的ASGI,说好的全双工异步通信呢?

难道是我哪里搞错了?不行,我得看看源码去!

## Django3.0的源码

一路点点点,翻了个遍,发现Django3.0与之前的2.2关于ASGI的区别就是多了下面两个文件:

![在这里插入图片描述](https://imgconvert.csdnimg.cn/aHR0cHM6Ly93d3cubGl1amlhbmdibG9nLmNvbS9zdGF0aWMvaW1hZ2VzL2Jsb2cvMTU3NTQyNzEwNDcyMi5wbmc?x-oss-process=image/format,png)

`django.core.asgi`很简单,一看就懂,如下所是:

```python

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请求

让我们看看它的其中一段代码:

```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']

    )

```

这就是我们前面在浏览器中发送ws请求,但是无法建立连接的原因!

如果`scope`的`type`属性不是`http`,那么弹出`ValueError`异常,并提示不支持该类连接!

再看看人家写的注释,明明白白的写着`Serve only HTTP connections. FIXME: Allow to override this.`。翻译过来就是只支持HTTP连接,请自己重写这部分内容修复这个缺陷。FIXME!FIXME!

## 总结

与Django3.0关于异步通信的初体验很不好,Django真的目前只提供了个接口,内部实现还没做

由于相关资料太少,多方查找,据说:

    Django会在后续的版本陆续实现完整的原生的异步通信能力,从同步机制切换到可兼容的异步机制

    目前3.0阶段,要与websocket通信依然得通过`django-channel`库,还不是原生支持

你可能感兴趣的:(Django3.x 初体验)