Neil  Morgan

Neil Morgan

1656831540

Como Começar Com As Visualizações Assíncronas Do Django

Escrever código assíncrono oferece a capacidade de acelerar seu aplicativo com pouco esforço. As versões do Django >= 3.1 suportam visualizações assíncronas, middleware e testes. Se você ainda não experimentou visualizações assíncronas, agora é um ótimo momento para colocá-las em prática.

Este tutorial mostra como começar com as visualizações assíncronas do Django.

Se você estiver interessado em aprender mais sobre o poder por trás do código assíncrono, juntamente com as diferenças entre threads, multiprocessamento e assíncrono em Python, confira meu artigo Acelerando o Python com simultaneidade, paralelismo e assíncrono .

Objetivos

Ao final deste tutorial, você deverá ser capaz de:

  1. Escreva uma visão assíncrona no Django
  2. Faça uma solicitação HTTP sem bloqueio em uma visualização do Django
  3. Simplifique as tarefas básicas em segundo plano com as visualizações assíncronas do Django
  4. Use sync_to_asyncpara fazer uma chamada síncrona dentro de uma visualização assíncrona
  5. Explique quando você deve e não deve usar visualizações assíncronas

Você também deve ser capaz de responder às seguintes perguntas:

  1. E se você fizer uma chamada síncrona dentro de uma visualização assíncrona?
  2. E se você fizer uma chamada síncrona e assíncrona dentro de uma visualização assíncrona?
  3. O aipo ainda é necessário com as visualizações assíncronas do Django?

Pré-requisitos

Contanto que você já esteja familiarizado com o próprio Django, adicionar funcionalidade assíncrona a visualizações não baseadas em classe é extremamente simples.

Dependências

  1. Python >= 3,10
  2. Django >= 4.0
  3. Uvicorn
  4. HTTPX

O que é ASGI?

ASGI significa Interface de Gateway de Servidor Assíncrono. É a continuação moderna e assíncrona do WSGI , fornecendo um padrão para a criação de aplicativos Web assíncronos baseados em Python.

Outra coisa que vale a pena mencionar é que ASGI é compatível com WSGI, tornando-se uma boa desculpa para mudar de um servidor WSGI como Gunicorn ou uWSGI para um servidor ASGI como Uvicorn ou Daphne , mesmo se você não estiver pronto para mudar para escrever aplicativos assíncronos .

Criando o aplicativo

Crie um novo diretório de projeto junto com um novo projeto Django:

$ mkdir django-async-views && cd django-async-views
$ python3.10 -m venv env
$ source env/bin/activate

(env)$ pip install django
(env)$ django-admin startproject hello_async .

Sinta-se à vontade para trocar virtualenv e Pip por Poetry ou Pipenv . Para saber mais, revise Ambientes Python Modernos .

O Django executará suas visualizações assíncronas se você estiver usando o servidor de desenvolvimento integrado, mas na verdade não as executará de forma assíncrona, então executaremos o Django com o Uvicorn.

Instale-o:

(env)$ pip install uvicorn

Para executar seu projeto com o Uvicorn, você usa o seguinte comando da raiz do seu projeto:

uvicorn {name of your project}.asgi:application

No nosso caso seria:

(env)$ uvicorn hello_async.asgi:application

Em seguida, vamos criar nossa primeira visualização assíncrona. Adicione um novo arquivo para manter suas visualizações na pasta "hello_async" e adicione a seguinte visualização:

# hello_async/views.py

from django.http import HttpResponse


async def index(request):
    return HttpResponse("Hello, async Django!")

Criar visualizações assíncronas no Django é tão simples quanto criar uma visualização síncrona -- tudo que você precisa fazer é adicionar a palavra- asyncchave.

Atualize os URLs:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index


urlpatterns = [
    path("admin/", admin.site.urls),
    path("", index),
]

Agora, em um terminal, na sua pasta raiz, execute:

(env)$ uvicorn hello_async.asgi:application --reload

O --reloadsinalizador diz ao Uvicorn para observar seus arquivos em busca de alterações e recarregar se encontrar algum. Isso foi provavelmente auto-explicativo.

Abra http://localhost:8000/ em seu navegador favorito:

Hello, async Django!

Não é a coisa mais excitante do mundo, mas, ei, é um começo. Vale a pena notar que executar esta visão com um servidor de desenvolvimento embutido do Django resultará exatamente na mesma funcionalidade e saída. Isso ocorre porque, na verdade, não estamos fazendo nada assíncrono no manipulador.

HTTPX

Vale a pena notar que o suporte assíncrono é totalmente compatível com versões anteriores, para que você possa misturar exibições assíncronas e sincronizadas, middleware e testes. O Django executará cada um no contexto de execução apropriado.

Para demonstrar isso, adicione algumas novas visualizações:

# hello_async/views.py

import asyncio
from time import sleep

import httpx
from django.http import HttpResponse


# helpers

async def http_call_async():
    for num in range(1, 6):
        await asyncio.sleep(1)
        print(num)
    async with httpx.AsyncClient() as client:
        r = await client.get("https://httpbin.org/")
        print(r)


def http_call_sync():
    for num in range(1, 6):
        sleep(1)
        print(num)
    r = httpx.get("https://httpbin.org/")
    print(r)


# views

async def index(request):
    return HttpResponse("Hello, async Django!")


async def async_view(request):
    loop = asyncio.get_event_loop()
    loop.create_task(http_call_async())
    return HttpResponse("Non-blocking HTTP request")


def sync_view(request):
    http_call_sync()
    return HttpResponse("Blocking HTTP request")

Atualize os URLs:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view


urlpatterns = [
    path("admin/", admin.site.urls),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Instale o HTTPX :

(env)$ pip install httpx

Com o servidor em execução, navegue até http://localhost:8000/async/ . Você deve ver imediatamente a resposta:

Non-blocking HTTP request

No seu terminal você deverá ver:

INFO:     127.0.0.1:60374 - "GET /async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Aqui, a resposta HTTP é enviada de volta antes da primeira chamada de suspensão.

Em seguida, navegue até http://localhost:8000/sync/ . Deve levar cerca de cinco segundos para obter a resposta:

Blocking HTTP request

Ligue para o terminal:

1
2
3
4
5
<Response [200 OK]>
INFO:     127.0.0.1:60375 - "GET /sync/ HTTP/1.1" 200 OK

Aqui, a resposta HTTP é enviada após o loop e a solicitação é https://httpbin.org/concluída.

Fumar algumas carnes

Para simular mais um cenário do mundo real de como você aproveitaria a assíncrona, vejamos como executar várias operações de forma assíncrona, agregar os resultados e devolvê-los ao chamador.

De volta ao URLconf do seu projeto, crie um novo caminho em smoke_some_meats:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view, smoke_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

De volta às suas visualizações, crie uma nova função auxiliar assíncrona chamada smoke. Esta função recebe dois parâmetros: uma lista de strings chamadas smokablese uma string chamada flavor. Estes padrões para uma lista de carnes defumadas e "Sweet Baby Ray's", respectivamente.

# hello_async/views.py

async def smoke(smokables: List[str] = None, flavor: str = "Sweet Baby Ray's") -> List[str]:
    """ Smokes some meats and applies the Sweet Baby Ray's """

    for smokable in smokables:
        print(f"Smoking some {smokable}...")
        print(f"Applying the {flavor}...")
        print(f"{smokable.capitalize()} smoked.")

    return len(smokables)

O loop for aplica o sabor de forma assíncrona (leia-se: Sweet Baby Ray's) aos fumáveis ​​(leia-se: carnes defumadas).

Não esqueça da importação:

from typing import List

Listé usado para recursos extras de digitação. Isso não é necessário e pode ser facilmente omitido (apenas nix a : List[str]seguir a declaração do parâmetro "smokables").

Em seguida, adicione mais dois auxiliares assíncronos:

async def get_smokables():
    print("Getting smokeables...")

    await asyncio.sleep(2)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning smokeable")
        return [
            "ribs",
            "brisket",
            "lemon chicken",
            "salmon",
            "bison sirloin",
            "sausage",
        ]


async def get_flavor():
    print("Getting flavor...")

    await asyncio.sleep(1)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning flavor")
        return random.choice(
            [
                "Sweet Baby Ray's",
                "Stubb's Original",
                "Famous Dave's",
            ]
        )

Certifique-se de adicionar a importação:

import random

Crie a visualização assíncrona que usa as funções assíncronas:

# hello_async/views.py

async def smoke_some_meats(request):
    results = await asyncio.gather(*[get_smokables(), get_flavor()])
    total = await asyncio.gather(*[smoke(results[0], results[1])])
    return HttpResponse(f"Smoked {total[0]} meats with {results[1]}!")

Essa exibição chama as funções get_smokablese get_flavorsimultaneamente. Como smokedepende dos resultados de get_smokablese get_flavor, costumávamos gatheraguardar a conclusão de cada tarefa assíncrona.

Lembre-se de que, em uma exibição de sincronização regular, get_smokablesseria get_flavortratado um de cada vez. Além disso, a visualização assíncrona produzirá a execução e permitirá que outras solicitações sejam processadas enquanto as tarefas assíncronas são processadas, o que permite que mais solicitações sejam tratadas pelo mesmo processo em um determinado período de tempo.

Por fim, uma resposta é retornada para informar ao usuário que sua deliciosa refeição de churrasco está pronta.

Excelente. Salve o arquivo, volte ao seu navegador e navegue até http://localhost:8000/smoke_some_meats/ . Deve levar alguns segundos para obter a resposta:

Smoked 6 meats with Sweet Baby Ray's!

Em seu console, você deverá ver:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Smoking some ribs...
Applying the Stubb's Original...
Ribs smoked.
Smoking some brisket...
Applying the Stubb's Original...
Brisket smoked.
Smoking some lemon chicken...
Applying the Stubb's Original...
Lemon chicken smoked.
Smoking some salmon...
Applying the Stubb's Original...
Salmon smoked.
Smoking some bison sirloin...
Applying the Stubb's Original...
Bison sirloin smoked.
Smoking some sausage...
Applying the Stubb's Original...
Sausage smoked.
INFO:     127.0.0.1:57501 - "GET /smoke_some_meats/ HTTP/1.1" 200 OK

Observe a ordem das seguintes instruções de impressão:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Isso é assincronicidade no trabalho: enquanto a get_smokablesfunção dorme, a get_flavorfunção termina o processamento.

Carnes Queimadas

Sincronizar chamada

P: E se você fizer uma chamada síncrona dentro de uma visualização assíncrona?

A mesma coisa que aconteceria se você chamasse uma função não assíncrona de uma exibição não assíncrona.

--

Para ilustrar isso, crie uma nova função auxiliar em seu views.py chamada oversmoke:

# hello_async/views.py

def oversmoke() -> None:
    """ If it's not dry, it must be uncooked """
    sleep(5)
    print("Who doesn't love burnt meats?")

Muito simples: estamos apenas aguardando de forma síncrona por cinco segundos.

Crie a view que chama esta função:

# hello_async/views.py

async def burn_some_meats(request):
    oversmoke()
    return HttpResponse(f"Burned some meats.")

Por fim, conecte a rota no URLconf do seu projeto:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view, smoke_some_meats, burn_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Visite a rota no navegador em http://localhost:8000/burn_some_meats :

Burned some meats.

Observe como levou cinco segundos para finalmente obter uma resposta do navegador. Você também deve ter recebido a saída do console ao mesmo tempo:

Who doesn't love burnt meats?
INFO:     127.0.0.1:40682 - "GET /burn_some_meats HTTP/1.1" 200 OK

Possivelmente vale a pena notar que a mesma coisa acontecerá independentemente do servidor que você estiver usando, seja ele baseado em WSGI ou ASGI.

Chamadas sincronizadas e assíncronas

P: E se você fizer uma chamada síncrona e assíncrona dentro de uma visualização assíncrona?

Não faça isso.

Visualizações síncronas e assíncronas tendem a funcionar melhor para diferentes propósitos. Se você tiver a funcionalidade de bloqueio em uma exibição assíncrona, na melhor das hipóteses não será melhor do que apenas usar uma exibição síncrona.

Sincronizar com assíncrono

Se você precisar fazer uma chamada síncrona dentro de uma visão assíncrona (como interagir com o banco de dados através do Django ORM, por exemplo), use sync_to_async como wrapper ou decorador.

Exemplo:

# hello_async/views.py

async def async_with_sync_view(request):
    loop = asyncio.get_event_loop()
    async_function = sync_to_async(http_call_sync, thread_sensitive=False)
    loop.create_task(async_function())
    return HttpResponse("Non-blocking HTTP request (via sync_to_async)")

Você notou que definimos o thread_sensitiveparâmetro para False? Isso significa que a função síncrona, http_call_sync, será executada em um novo thread. Revise os documentos para obter mais informações.

Adicione a importação ao topo:

from asgiref.sync import sync_to_async

Adicione o URL:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import (
    index,
    async_view,
    sync_view,
    smoke_some_meats,
    burn_some_meats,
    async_with_sync_view
)


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("sync_to_async/", async_with_sync_view),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Teste-o em seu navegador em http://localhost:8000/sync_to_async/ .

No seu terminal você deverá ver:

INFO:     127.0.0.1:61365 - "GET /sync_to_async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Usando sync_to_async, a chamada síncrona de bloqueio foi processada em um thread em segundo plano, permitindo que a resposta HTTP fosse enviada de volta antes da primeira chamada de suspensão.

Aipo e visualizações assíncronas

P: O Celery ainda é necessário com as visualizações assíncronas do Django?

Depende.

As visualizações assíncronas do Django oferecem funcionalidade semelhante a uma fila de tarefas ou mensagens sem a complexidade. Se você está usando (ou está considerando) o Django e quer fazer algo simples (e não se importa com confiabilidade), as visualizações assíncronas são uma ótima maneira de fazer isso de forma rápida e fácil. Se você precisar executar processos em segundo plano muito mais pesados ​​e de longa duração, ainda precisará usar o Celery ou o RQ.

Deve-se observar que, para usar exibições assíncronas de maneira eficaz, você deve ter apenas chamadas assíncronas na exibição. As filas de tarefas, por outro lado, usam trabalhadores em processos separados e, portanto, são capazes de executar chamadas síncronas em segundo plano, em vários servidores.

A propósito, você não deve escolher entre exibições assíncronas e uma fila de mensagens - você pode usá-las facilmente em conjunto. Por exemplo: você pode usar uma exibição assíncrona para enviar um email ou fazer uma modificação única no banco de dados, mas fazer com que o Celery limpe seu banco de dados em um horário agendado todas as noites ou gere e envie relatórios de clientes.

Quando usar

Para projetos greenfield, se você gosta de assíncrona, aproveite as visualizações assíncronas e escreva seus processos de E/S de maneira assíncrona o máximo possível. Dito isso, se a maioria de suas visualizações precisar apenas fazer chamadas para um banco de dados e fazer algum processamento básico antes de retornar os dados, você não verá muito aumento (se houver) sobre apenas manter as visualizações de sincronização.

Para projetos brownfield, se você tiver pouco ou nenhum processo de E/S, fique com as visualizações de sincronização. Se você tiver vários processos de E/S, avalie como será fácil reescrevê-los de maneira assíncrona. Reescrever a E/S de sincronização para assíncrona não é fácil, portanto, você provavelmente desejará otimizar sua E/S de sincronização e exibições antes de tentar reescrever para assíncrona. Além disso, nunca é uma boa ideia misturar processos de sincronização com suas visualizações assíncronas.

Na produção, certifique-se de usar o Gunicorn para gerenciar o Uvicorn para aproveitar a simultaneidade (via Uvicorn) e o paralelismo (via trabalhadores do Gunicorn):

gunicorn -w 3 -k uvicorn.workers.UvicornWorker hello_async.asgi:application

Conclusão

Concluindo, embora este seja um caso de uso simples, ele deve lhe dar uma ideia aproximada das possibilidades que as visões assíncronas do Django abrem. Algumas outras coisas para tentar em suas visualizações assíncronas são enviar e-mails, chamar APIs de terceiros e ler/gravar em arquivos.

Fonte:  https://testdrive.io

#django #async 

What is GEEK

Buddha Community

Como Começar Com As Visualizações Assíncronas Do Django
Ahebwe  Oscar

Ahebwe Oscar

1620177818

Django admin full Customization step by step

Welcome to my blog , hey everyone in this article you learn how to customize the Django app and view in the article you will know how to register  and unregister  models from the admin view how to add filtering how to add a custom input field, and a button that triggers an action on all objects and even how to change the look of your app and page using the Django suit package let’s get started.

Database

Custom Titles of Django Admin

Exclude in Django Admin

Fields in Django Admin

#django #create super user django #customize django admin dashboard #django admin #django admin custom field display #django admin customization #django admin full customization #django admin interface #django admin register all models #django customization

Ahebwe  Oscar

Ahebwe Oscar

1620185280

How model queries work in Django

How model queries work in Django

Welcome to my blog, hey everyone in this article we are going to be working with queries in Django so for any web app that you build your going to want to write a query so you can retrieve information from your database so in this article I’ll be showing you all the different ways that you can write queries and it should cover about 90% of the cases that you’ll have when you’re writing your code the other 10% depend on your specific use case you may have to get more complicated but for the most part what I cover in this article should be able to help you so let’s start with the model that I have I’ve already created it.

**Read More : **How to make Chatbot in Python.

Read More : Django Admin Full Customization step by step

let’s just get into this diagram that I made so in here:

django queries aboutDescribe each parameter in Django querset

we’re making a simple query for the myModel table so we want to pull out all the information in the database so we have this variable which is gonna hold a return value and we have our myModel models so this is simply the myModel model name so whatever you named your model just make sure you specify that and we’re gonna access the objects attribute once we get that object’s attribute we can simply use the all method and this will return all the information in the database so we’re gonna start with all and then we will go into getting single items filtering that data and go to our command prompt.

Here and we’ll actually start making our queries from here to do this let’s just go ahead and run** Python manage.py shell** and I am in my project file so make sure you’re in there when you start and what this does is it gives us an interactive shell to actually start working with our data so this is a lot like the Python shell but because we did manage.py it allows us to do things a Django way and actually query our database now open up the command prompt and let’s go ahead and start making our first queries.

#django #django model queries #django orm #django queries #django query #model django query #model query #query with django

Ananya Gupta

Ananya Gupta

1597123834

Main Pros and Cons of Django As A Web Framework for Python Developers

Django depicts itself as “the web system for fussbudgets with cutoff times”. It was intended to help Python engineers take applications from idea to consummation as fast as could be expected under the circumstances.

It permits fast turn of events on the off chance that you need to make a CRUD application with batteries included. With Django, you won’t need to rehash an already solved problem. It just works and lets you center around your business rationale and making something clients can utilize.

Pros of Django

“Batteries included” theory

The standard behind batteries-included methods normal usefulness for building web applications accompanies the system, not as isolated libraries.

Django incorporates much usefulness you can use to deal with normal web advancement undertakings. Here are some significant level functionalities that Django gives you, which else you need to stay together if you somehow happened to utilize a small scale structure:

ORM

Database relocations

Client validation

Administrator board

Structures

Normalized structure

Django as a system proposes the right structure of an undertaking. That structure helps designers in making sense of how and where to execute any new component.

With a generally acknowledged venture structure that is like numerous tasks, it is a lot simpler to discover online good arrangements or approach the network for help. There are numerous energetic Python designers who will assist you with comprehending any issue you may experience.

Django applications

Django applications (or applications for short) permit designers to separate a task into numerous applications. An application is whatever is introduced by putting in settings.INSTALLED_APPS. This makes it simpler for engineers to add usefulness to the web application by coordinating outer Django applications into the venture.

There are many reusable modules and applications to accelerate your turn of events learn through Online Django Class and Check the Django website.

Secure of course

Django gives great security assurance out of the crate and incorporates avoidance components for basic assaults like SQL Injection (XSS) and Cross-site Request Forgery (CSRF). You can discover more subtleties in the official security diagram control.

REST structure for building APIs

Django REST Framework, commonly condensed “DRF”, is a Python library for building APIs. It has secluded and adaptable engineering that functions admirably for both straightforward and complex web APIs.

DRF gives a lot of verification and authorization strategies out of the case. It is an adaptable, full-included library with measured and adjustable engineering. It accompanies nonexclusive classes for CRUD tasks and an implicit API program for testing API endpoints.

GraphQL structure for building APIs

Huge REST APIs regularly require a lot of solicitations to various endpoints to recover every single required datum. GraphQL it’s a question language that permits us to share related information in a lot simpler design. For a prologue to GraphQL and an outline of its ideas, if it’s not too much trouble allude to the authority GraphQL documentation.

Graphene-Django gives reflections that make it simple to add GraphQL usefulness to your Django venture. Ordinary Django models, structures, validation, consent arrangements, and different functionalities can be reused to manufacture GraphQL blueprint. It additionally gives an implicit API program for testing API endpoints.

Cons of Django

Django ORM

Django ORM, made before SQLAlchemy existed, is currently much sub-par compared to SQLAlchemy. It depends on the Active Record design which is more regrettable than the Unit of Work design embraced by SQLAlchemy. This implies, in Django, models can “spare” themselves and exchanges are off as a matter of course, they are a bit of hindsight. Peruse more in Why I kind of aversion Django.

Django advances course popularity increses day by day:

Django is huge and is viewed as strong bit of programming. This permits the network to create several reusable modules and applications yet has additionally restricted the speed of advancement of the Django. On head of that Django needs to keep up in reverse similarity, so it advances gradually.

Rundown - Should I use Django as a Python designer?

While Django ORM isn’t as adaptable as SQLAlchemy and the enormous environment of reusable modules and applications hinders structure advancement - plainly Django ought to be the best option web system for Python engineers.

Elective, light systems, similar to Flask, while offering a retreat from Django huge biological system and designs, in the long haul can require substantially more additional libraries and usefulness, in the end making many experienced Python engineers winding up wishing they’d began with Django.

Django undertaking’s security and network have become enormously over the previous decade since the system’s creation. Official documentation and instructional exercises are probably the best anyplace in programming advancement. With each delivery, Django keeps on including huge new usefulness.

#django online training #django online course #online django course #django course #django training #django certification course

Marget D

Marget D

1626077187

4 key Features of Django Framework that Make it the Best Amongst all!

Django is one of the popular python based open-source web frameworks mainly used by the developers who like to have rapid development along with the clean pragmatic design.

Read this blog to know the various Django Features with details.

#django framework #django web development #django development company #django development services #python django development company #python django development

Neil  Morgan

Neil Morgan

1656831540

Como Começar Com As Visualizações Assíncronas Do Django

Escrever código assíncrono oferece a capacidade de acelerar seu aplicativo com pouco esforço. As versões do Django >= 3.1 suportam visualizações assíncronas, middleware e testes. Se você ainda não experimentou visualizações assíncronas, agora é um ótimo momento para colocá-las em prática.

Este tutorial mostra como começar com as visualizações assíncronas do Django.

Se você estiver interessado em aprender mais sobre o poder por trás do código assíncrono, juntamente com as diferenças entre threads, multiprocessamento e assíncrono em Python, confira meu artigo Acelerando o Python com simultaneidade, paralelismo e assíncrono .

Objetivos

Ao final deste tutorial, você deverá ser capaz de:

  1. Escreva uma visão assíncrona no Django
  2. Faça uma solicitação HTTP sem bloqueio em uma visualização do Django
  3. Simplifique as tarefas básicas em segundo plano com as visualizações assíncronas do Django
  4. Use sync_to_asyncpara fazer uma chamada síncrona dentro de uma visualização assíncrona
  5. Explique quando você deve e não deve usar visualizações assíncronas

Você também deve ser capaz de responder às seguintes perguntas:

  1. E se você fizer uma chamada síncrona dentro de uma visualização assíncrona?
  2. E se você fizer uma chamada síncrona e assíncrona dentro de uma visualização assíncrona?
  3. O aipo ainda é necessário com as visualizações assíncronas do Django?

Pré-requisitos

Contanto que você já esteja familiarizado com o próprio Django, adicionar funcionalidade assíncrona a visualizações não baseadas em classe é extremamente simples.

Dependências

  1. Python >= 3,10
  2. Django >= 4.0
  3. Uvicorn
  4. HTTPX

O que é ASGI?

ASGI significa Interface de Gateway de Servidor Assíncrono. É a continuação moderna e assíncrona do WSGI , fornecendo um padrão para a criação de aplicativos Web assíncronos baseados em Python.

Outra coisa que vale a pena mencionar é que ASGI é compatível com WSGI, tornando-se uma boa desculpa para mudar de um servidor WSGI como Gunicorn ou uWSGI para um servidor ASGI como Uvicorn ou Daphne , mesmo se você não estiver pronto para mudar para escrever aplicativos assíncronos .

Criando o aplicativo

Crie um novo diretório de projeto junto com um novo projeto Django:

$ mkdir django-async-views && cd django-async-views
$ python3.10 -m venv env
$ source env/bin/activate

(env)$ pip install django
(env)$ django-admin startproject hello_async .

Sinta-se à vontade para trocar virtualenv e Pip por Poetry ou Pipenv . Para saber mais, revise Ambientes Python Modernos .

O Django executará suas visualizações assíncronas se você estiver usando o servidor de desenvolvimento integrado, mas na verdade não as executará de forma assíncrona, então executaremos o Django com o Uvicorn.

Instale-o:

(env)$ pip install uvicorn

Para executar seu projeto com o Uvicorn, você usa o seguinte comando da raiz do seu projeto:

uvicorn {name of your project}.asgi:application

No nosso caso seria:

(env)$ uvicorn hello_async.asgi:application

Em seguida, vamos criar nossa primeira visualização assíncrona. Adicione um novo arquivo para manter suas visualizações na pasta "hello_async" e adicione a seguinte visualização:

# hello_async/views.py

from django.http import HttpResponse


async def index(request):
    return HttpResponse("Hello, async Django!")

Criar visualizações assíncronas no Django é tão simples quanto criar uma visualização síncrona -- tudo que você precisa fazer é adicionar a palavra- asyncchave.

Atualize os URLs:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index


urlpatterns = [
    path("admin/", admin.site.urls),
    path("", index),
]

Agora, em um terminal, na sua pasta raiz, execute:

(env)$ uvicorn hello_async.asgi:application --reload

O --reloadsinalizador diz ao Uvicorn para observar seus arquivos em busca de alterações e recarregar se encontrar algum. Isso foi provavelmente auto-explicativo.

Abra http://localhost:8000/ em seu navegador favorito:

Hello, async Django!

Não é a coisa mais excitante do mundo, mas, ei, é um começo. Vale a pena notar que executar esta visão com um servidor de desenvolvimento embutido do Django resultará exatamente na mesma funcionalidade e saída. Isso ocorre porque, na verdade, não estamos fazendo nada assíncrono no manipulador.

HTTPX

Vale a pena notar que o suporte assíncrono é totalmente compatível com versões anteriores, para que você possa misturar exibições assíncronas e sincronizadas, middleware e testes. O Django executará cada um no contexto de execução apropriado.

Para demonstrar isso, adicione algumas novas visualizações:

# hello_async/views.py

import asyncio
from time import sleep

import httpx
from django.http import HttpResponse


# helpers

async def http_call_async():
    for num in range(1, 6):
        await asyncio.sleep(1)
        print(num)
    async with httpx.AsyncClient() as client:
        r = await client.get("https://httpbin.org/")
        print(r)


def http_call_sync():
    for num in range(1, 6):
        sleep(1)
        print(num)
    r = httpx.get("https://httpbin.org/")
    print(r)


# views

async def index(request):
    return HttpResponse("Hello, async Django!")


async def async_view(request):
    loop = asyncio.get_event_loop()
    loop.create_task(http_call_async())
    return HttpResponse("Non-blocking HTTP request")


def sync_view(request):
    http_call_sync()
    return HttpResponse("Blocking HTTP request")

Atualize os URLs:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view


urlpatterns = [
    path("admin/", admin.site.urls),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Instale o HTTPX :

(env)$ pip install httpx

Com o servidor em execução, navegue até http://localhost:8000/async/ . Você deve ver imediatamente a resposta:

Non-blocking HTTP request

No seu terminal você deverá ver:

INFO:     127.0.0.1:60374 - "GET /async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Aqui, a resposta HTTP é enviada de volta antes da primeira chamada de suspensão.

Em seguida, navegue até http://localhost:8000/sync/ . Deve levar cerca de cinco segundos para obter a resposta:

Blocking HTTP request

Ligue para o terminal:

1
2
3
4
5
<Response [200 OK]>
INFO:     127.0.0.1:60375 - "GET /sync/ HTTP/1.1" 200 OK

Aqui, a resposta HTTP é enviada após o loop e a solicitação é https://httpbin.org/concluída.

Fumar algumas carnes

Para simular mais um cenário do mundo real de como você aproveitaria a assíncrona, vejamos como executar várias operações de forma assíncrona, agregar os resultados e devolvê-los ao chamador.

De volta ao URLconf do seu projeto, crie um novo caminho em smoke_some_meats:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view, smoke_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

De volta às suas visualizações, crie uma nova função auxiliar assíncrona chamada smoke. Esta função recebe dois parâmetros: uma lista de strings chamadas smokablese uma string chamada flavor. Estes padrões para uma lista de carnes defumadas e "Sweet Baby Ray's", respectivamente.

# hello_async/views.py

async def smoke(smokables: List[str] = None, flavor: str = "Sweet Baby Ray's") -> List[str]:
    """ Smokes some meats and applies the Sweet Baby Ray's """

    for smokable in smokables:
        print(f"Smoking some {smokable}...")
        print(f"Applying the {flavor}...")
        print(f"{smokable.capitalize()} smoked.")

    return len(smokables)

O loop for aplica o sabor de forma assíncrona (leia-se: Sweet Baby Ray's) aos fumáveis ​​(leia-se: carnes defumadas).

Não esqueça da importação:

from typing import List

Listé usado para recursos extras de digitação. Isso não é necessário e pode ser facilmente omitido (apenas nix a : List[str]seguir a declaração do parâmetro "smokables").

Em seguida, adicione mais dois auxiliares assíncronos:

async def get_smokables():
    print("Getting smokeables...")

    await asyncio.sleep(2)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning smokeable")
        return [
            "ribs",
            "brisket",
            "lemon chicken",
            "salmon",
            "bison sirloin",
            "sausage",
        ]


async def get_flavor():
    print("Getting flavor...")

    await asyncio.sleep(1)
    async with httpx.AsyncClient() as client:
        await client.get("https://httpbin.org/")

        print("Returning flavor")
        return random.choice(
            [
                "Sweet Baby Ray's",
                "Stubb's Original",
                "Famous Dave's",
            ]
        )

Certifique-se de adicionar a importação:

import random

Crie a visualização assíncrona que usa as funções assíncronas:

# hello_async/views.py

async def smoke_some_meats(request):
    results = await asyncio.gather(*[get_smokables(), get_flavor()])
    total = await asyncio.gather(*[smoke(results[0], results[1])])
    return HttpResponse(f"Smoked {total[0]} meats with {results[1]}!")

Essa exibição chama as funções get_smokablese get_flavorsimultaneamente. Como smokedepende dos resultados de get_smokablese get_flavor, costumávamos gatheraguardar a conclusão de cada tarefa assíncrona.

Lembre-se de que, em uma exibição de sincronização regular, get_smokablesseria get_flavortratado um de cada vez. Além disso, a visualização assíncrona produzirá a execução e permitirá que outras solicitações sejam processadas enquanto as tarefas assíncronas são processadas, o que permite que mais solicitações sejam tratadas pelo mesmo processo em um determinado período de tempo.

Por fim, uma resposta é retornada para informar ao usuário que sua deliciosa refeição de churrasco está pronta.

Excelente. Salve o arquivo, volte ao seu navegador e navegue até http://localhost:8000/smoke_some_meats/ . Deve levar alguns segundos para obter a resposta:

Smoked 6 meats with Sweet Baby Ray's!

Em seu console, você deverá ver:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Smoking some ribs...
Applying the Stubb's Original...
Ribs smoked.
Smoking some brisket...
Applying the Stubb's Original...
Brisket smoked.
Smoking some lemon chicken...
Applying the Stubb's Original...
Lemon chicken smoked.
Smoking some salmon...
Applying the Stubb's Original...
Salmon smoked.
Smoking some bison sirloin...
Applying the Stubb's Original...
Bison sirloin smoked.
Smoking some sausage...
Applying the Stubb's Original...
Sausage smoked.
INFO:     127.0.0.1:57501 - "GET /smoke_some_meats/ HTTP/1.1" 200 OK

Observe a ordem das seguintes instruções de impressão:

Getting smokeables...
Getting flavor...
Returning flavor
Returning smokeable

Isso é assincronicidade no trabalho: enquanto a get_smokablesfunção dorme, a get_flavorfunção termina o processamento.

Carnes Queimadas

Sincronizar chamada

P: E se você fizer uma chamada síncrona dentro de uma visualização assíncrona?

A mesma coisa que aconteceria se você chamasse uma função não assíncrona de uma exibição não assíncrona.

--

Para ilustrar isso, crie uma nova função auxiliar em seu views.py chamada oversmoke:

# hello_async/views.py

def oversmoke() -> None:
    """ If it's not dry, it must be uncooked """
    sleep(5)
    print("Who doesn't love burnt meats?")

Muito simples: estamos apenas aguardando de forma síncrona por cinco segundos.

Crie a view que chama esta função:

# hello_async/views.py

async def burn_some_meats(request):
    oversmoke()
    return HttpResponse(f"Burned some meats.")

Por fim, conecte a rota no URLconf do seu projeto:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import index, async_view, sync_view, smoke_some_meats, burn_some_meats


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Visite a rota no navegador em http://localhost:8000/burn_some_meats :

Burned some meats.

Observe como levou cinco segundos para finalmente obter uma resposta do navegador. Você também deve ter recebido a saída do console ao mesmo tempo:

Who doesn't love burnt meats?
INFO:     127.0.0.1:40682 - "GET /burn_some_meats HTTP/1.1" 200 OK

Possivelmente vale a pena notar que a mesma coisa acontecerá independentemente do servidor que você estiver usando, seja ele baseado em WSGI ou ASGI.

Chamadas sincronizadas e assíncronas

P: E se você fizer uma chamada síncrona e assíncrona dentro de uma visualização assíncrona?

Não faça isso.

Visualizações síncronas e assíncronas tendem a funcionar melhor para diferentes propósitos. Se você tiver a funcionalidade de bloqueio em uma exibição assíncrona, na melhor das hipóteses não será melhor do que apenas usar uma exibição síncrona.

Sincronizar com assíncrono

Se você precisar fazer uma chamada síncrona dentro de uma visão assíncrona (como interagir com o banco de dados através do Django ORM, por exemplo), use sync_to_async como wrapper ou decorador.

Exemplo:

# hello_async/views.py

async def async_with_sync_view(request):
    loop = asyncio.get_event_loop()
    async_function = sync_to_async(http_call_sync, thread_sensitive=False)
    loop.create_task(async_function())
    return HttpResponse("Non-blocking HTTP request (via sync_to_async)")

Você notou que definimos o thread_sensitiveparâmetro para False? Isso significa que a função síncrona, http_call_sync, será executada em um novo thread. Revise os documentos para obter mais informações.

Adicione a importação ao topo:

from asgiref.sync import sync_to_async

Adicione o URL:

# hello_async/urls.py

from django.contrib import admin
from django.urls import path

from hello_async.views import (
    index,
    async_view,
    sync_view,
    smoke_some_meats,
    burn_some_meats,
    async_with_sync_view
)


urlpatterns = [
    path("admin/", admin.site.urls),
    path("smoke_some_meats/", smoke_some_meats),
    path("burn_some_meats/", burn_some_meats),
    path("sync_to_async/", async_with_sync_view),
    path("async/", async_view),
    path("sync/", sync_view),
    path("", index),
]

Teste-o em seu navegador em http://localhost:8000/sync_to_async/ .

No seu terminal você deverá ver:

INFO:     127.0.0.1:61365 - "GET /sync_to_async/ HTTP/1.1" 200 OK
1
2
3
4
5
<Response [200 OK]>

Usando sync_to_async, a chamada síncrona de bloqueio foi processada em um thread em segundo plano, permitindo que a resposta HTTP fosse enviada de volta antes da primeira chamada de suspensão.

Aipo e visualizações assíncronas

P: O Celery ainda é necessário com as visualizações assíncronas do Django?

Depende.

As visualizações assíncronas do Django oferecem funcionalidade semelhante a uma fila de tarefas ou mensagens sem a complexidade. Se você está usando (ou está considerando) o Django e quer fazer algo simples (e não se importa com confiabilidade), as visualizações assíncronas são uma ótima maneira de fazer isso de forma rápida e fácil. Se você precisar executar processos em segundo plano muito mais pesados ​​e de longa duração, ainda precisará usar o Celery ou o RQ.

Deve-se observar que, para usar exibições assíncronas de maneira eficaz, você deve ter apenas chamadas assíncronas na exibição. As filas de tarefas, por outro lado, usam trabalhadores em processos separados e, portanto, são capazes de executar chamadas síncronas em segundo plano, em vários servidores.

A propósito, você não deve escolher entre exibições assíncronas e uma fila de mensagens - você pode usá-las facilmente em conjunto. Por exemplo: você pode usar uma exibição assíncrona para enviar um email ou fazer uma modificação única no banco de dados, mas fazer com que o Celery limpe seu banco de dados em um horário agendado todas as noites ou gere e envie relatórios de clientes.

Quando usar

Para projetos greenfield, se você gosta de assíncrona, aproveite as visualizações assíncronas e escreva seus processos de E/S de maneira assíncrona o máximo possível. Dito isso, se a maioria de suas visualizações precisar apenas fazer chamadas para um banco de dados e fazer algum processamento básico antes de retornar os dados, você não verá muito aumento (se houver) sobre apenas manter as visualizações de sincronização.

Para projetos brownfield, se você tiver pouco ou nenhum processo de E/S, fique com as visualizações de sincronização. Se você tiver vários processos de E/S, avalie como será fácil reescrevê-los de maneira assíncrona. Reescrever a E/S de sincronização para assíncrona não é fácil, portanto, você provavelmente desejará otimizar sua E/S de sincronização e exibições antes de tentar reescrever para assíncrona. Além disso, nunca é uma boa ideia misturar processos de sincronização com suas visualizações assíncronas.

Na produção, certifique-se de usar o Gunicorn para gerenciar o Uvicorn para aproveitar a simultaneidade (via Uvicorn) e o paralelismo (via trabalhadores do Gunicorn):

gunicorn -w 3 -k uvicorn.workers.UvicornWorker hello_async.asgi:application

Conclusão

Concluindo, embora este seja um caso de uso simples, ele deve lhe dar uma ideia aproximada das possibilidades que as visões assíncronas do Django abrem. Algumas outras coisas para tentar em suas visualizações assíncronas são enviar e-mails, chamar APIs de terceiros e ler/gravar em arquivos.

Fonte:  https://testdrive.io

#django #async