zoukankan      html  css  js  c++  java
  • Django3.1异步视图抢先看

    Django 3.1将于2020年8月发布!从3.1版本开始,Django将逐步原生支持异步,比如异步视图和中间件。

    Django 3.1只支持Python 3.6、3.7、3.8以及更高版本。

    下面重点介绍Django3.1的新特性:

    1. 异步视图

    在Django3.1中,要定义一个异步视图很简单,只需使用Python的async def语法,Django会自动探测到它们,并在异步上下文中运行它们。异步视图有很多优点,比如能够在不使用Python线程的情况下为数百个连接提供服务,允许使用慢速流、长轮询和其他的响应类型等等。

    async def my_view(request):
        await asyncio.sleep(0.5)
        return HttpResponse('Hello, async world!')
    

    无论你是运行在WSGI还是ASGI模式,都支持所有异步特性。

    但是,在WSGI模式下使用异步代码可能会有性能损失,因为此时异步视图将在它们自己的一次性事件循环中运行,这意味着你虽然可以使用异步特性,如并行的异步HTTP请求,但却无法获得异步堆栈的好处。

    我们可以随心所欲地混合异步和同步的视图、中间件和测试,Django会确保我们始终获得正确的执行上下文。但是,Django官方建议大多数时候依然使用同步视图,只有在真正有需求时使用异步视图,不过这完全取决于你的选择,你可以任性的都使用异步视图。

    Django3.1版本中的ORM、缓存层和其他执行长时间网络调用的代码还暂时不支持异步访问,会在后期发布的版本中增加对它们的支持。(我的官网https://www.liujiangblog.com中也会持续关注并更新最新的内容和变化。)Django对异步的支持完全向后兼容,对现有的同步代码没有速度限制,它不会对任何现有的Django项目产生明显的影响。

    下面是另外一个例子:

    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/

  • 相关阅读:
    Excel 单元格不能设置超链接
    jenkins 构建到最后报权限的问题
    xshell远程登录工具的星号密码查看方法
    xshell的一些常用配置
    zabbix 添加自动发现端口并监控
    细说websocket -Node篇
    让PHP更快的提供文件下载
    一个只有99行代码的JS流程框架
    40行代码的人脸识别实践
    PHP异步:在PHP中使用 fsockopen curl 实现类似异步处理的功能
  • 原文地址:https://www.cnblogs.com/django-dev/p/12915114.html
Copyright © 2011-2022 走看看