Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

886
Visualizações
Django 3.1: StreamingHttpResponse con un generador asíncrono

La documentación para Django 3.1 dice esto sobre las vistas asíncronas:

Los principales beneficios son la capacidad de atender cientos de conexiones sin usar subprocesos de Python. Esto le permite usar transmisiones lentas, encuestas largas y otros tipos de respuestas emocionantes.

Creo que "transmisión lenta" significa que podríamos implementar una vista SSE sin monopolizar un hilo por cliente, así que traté de esbozar una vista simple, así:

 async def stream(request): async def event_stream(): while True: yield 'data: The server time is: %s\n\n' % datetime.datetime.now() await asyncio.sleep(1) return StreamingHttpResponse(event_stream(), content_type='text/event-stream')

(nota: adapté el código de esta respuesta )

Desafortunadamente, cuando se invoca esta vista, genera la siguiente excepción:

 Traceback (most recent call last): File "/usr/local/lib/python3.7/site-packages/asgiref/sync.py", line 330, in thread_handler raise exc_info[1] File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 38, in inner response = await get_response(request) File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 231, in _get_response_async response = await wrapped_callback(request, *callback_args, **callback_kwargs) File "./chat/views.py", line 144, in watch return StreamingHttpResponse(event_stream(), content_type='text/event-stream') File "/usr/local/lib/python3.7/site-packages/django/http/response.py", line 367, in __init__ self.streaming_content = streaming_content File "/usr/local/lib/python3.7/site-packages/django/http/response.py", line 382, in streaming_content self._set_streaming_content(value) File "/usr/local/lib/python3.7/site-packages/django/http/response.py", line 386, in _set_streaming_content self._iterator = iter(value) TypeError: 'async_generator' object is not iterable

Para mí, esto muestra que StreamingHttpResponse actualmente no admite generadores asíncronos.

Traté de modificar StreamingHttpResponse para usar async for pero no pude hacer mucho.

¿Alguna idea de cómo podría hacer eso?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Honestamente, Django no lo admite de forma nativa, pero tengo una solución para usted usando Daphne (que también se usa en los canales de Django).

Creó su propia clase StreamingHttpResponse que puede recuperar el flujo de datos de los métodos asíncronos y proporcionarlos a la parte síncrona de Django.

 import asyncio # By design asyncio does not allow its event loop to be nested. # Trying to do so will give the error "RuntimeError: This event loop is already running". # This library solves that problem. import nest_asyncio from django.http.response import StreamingHttpResponse class AsyncStreamingHttpResponse(StreamingHttpResponse): def __init__(self, streaming_content=(), *args, **kwargs): sync_streaming_content = self.get_sync_iterator(streaming_content) super().__init__(streaming_content=sync_streaming_content, *args, **kwargs) @staticmethod async def convert_async_iterable(stream): """Accepts async_generator and async_iterator""" return iter([chunk async for chunk in stream]) def get_sync_iterator(self, async_iterable): nest_asyncio.apply() loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) result = loop.run_until_complete(self.convert_async_iterable(async_iterable)) return result

Además, deberá ejecutar su servidor web Django usando Daphne para admitir eventos enviados por el servidor (SSE) correctamente. Es oficialmente compatible con "Django Software Foundation" y tiene una sintaxis similar a gunicorn , pero usa asgi.py en lugar de wsgi.py .

Para usarlo, puede instalarlo usando: pip install daphne

Y cambie el comando desde: python manage.py runserver
a algo como: daphne -b 0.0.0.0 -p 8000 sse_demo.asgi:application .

No estoy seguro de si funcionará con gunicorn .

Avísame si tienes más preguntas.

over 4 years ago · Santiago Trujillo Relatório

0

Creé un decorador llamado stream que se puede usar con una función de rutina para que sea compatible con StreamingHttpResponse de Django. Aquí hay un ejemplo:

 import asyncio import functools from django.http import StreamingHttpResponse def stream(coroutine_function): @functools.wraps(coroutine_function) def wrapper(): coroutine = coroutine_function() try: while True: yield asyncio.run(coroutine.__anext__()) except StopAsyncIteration: pass return wrapper @stream async def chunks(): for char in 'Hello, world!': yield char await asyncio.sleep(1) async def index(request): return StreamingHttpResponse(chunks())

También necesitaba agregar nest_asyncio y llamar a apply() en la parte superior del archivo settings.py como:

 import nest_asyncio nest_asyncio.apply()

La dependencia nest_asyncio admite llamar a asyncio.run desde la función wrapper creada por el decorador de stream .

Finalmente, el asgi de Django se puede ejecutar usando uvicorn a través gunicorn como:

 $ gunicorn -k uvicorn.workers.UvicornWorker www.asgi:application
over 4 years ago · Santiago Trujillo Relatório

0

Otra forma de hacer SSE es usar la biblioteca especial django-eventstream :

Agregue lo siguiente a la página HTML que consumirá datos:

 <script src="{% static 'django_eventstream/eventsource.min.js' %}"></script> <script src="{% static 'django_eventstream/reconnecting-eventsource.js' %}"></script> var es = new ReconnectingEventSource('/events/'); es.addEventListener('message', function (e) { console.log(e.data); }, false); es.addEventListener('stream-reset', function (e) { // ... client fell behind, reinitialize ... }, false);

Para el backend, deberá configurar correctamente Django y, más adelante, podrá llamar al siguiente método en cualquier vista/tarea/señal/método que necesite hacer Server Side Event (SSE):

Agregue la siguiente vista que producirá datos (eventos):

 # from django_eventstream import send_event send_event('test', 'message', {'text': 'hello world'})
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda