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/

相关文章
相关标签/搜索