# documentación de Django - 5.2.8

# Soporte asíncrono

Django tiene soporte para escribir vistas asíncronas («async»), junto con una pila de solicitudes completamente habilitada para el asincronismo si se está ejecutando bajo ASGI. Las vistas asíncronas seguirán funcionando con WSGI, pero con problemas de rendimiento y sin la capacidad de tener solicitudes prolongadas eficientes.

Todavía estamos trabajando en el soporte asíncrono para el ORM y otras partes de Django. Puede esperar ver esto en futuras versiones. Por ahora, puede usar el adaptador `sync_to_async()` para interactuar con las partes de sincronización de Django. También hay una amplia gama de bibliotecas asíncronas y nativas de Python con las que puede integrarse.

## Vistas asincrónicas

Cualquier vista puede declararse asincrónica haciendo que la parte invocable devuelva una corrutina; comúnmente, esto se hace usando `async def`. Para una vista basada en funciones, esto significa declarar la vista completa usando `async def`. Para una vista basada en clases, esto significa declarar los manejadors de métodos HTTP como `get()` and `post()` como `async def` (no su `__init__()` ni `as_view()`).

Nota

Django uses `asgiref.sync.iscoroutinefunction` to test if your view is asynchronous or not. If you implement your own method of returning a coroutine, ensure you use `asgiref.sync.markcoroutinefunction` so this function returns `True`.

En un servidor WSGI, las vistas asíncronas se ejecutarán en su propio bucle de eventos. Esto significa que puede usar funciones asíncronas, como peticiones HTTP asíncronas concurrentes, sin ningún problema, pero no obtendrá los beneficios de una pila asíncrona.

Los principales beneficios son la capacidad de dar servicio a cientos de conexiones sin utilizar hilos de Python. Esto le permite usar transmisión lenta, sondeos largos (long-polling) y otros tipos de respuesta interesantes.

Si desea usarlos, deberá desplegar Django usando ASGI en su lugar.

Advertencia

Solo obtendrá los beneficios de una pila de peticiones totalmente asincrónica si no tiene ningún middleware sincrónico cargado en su sitio. Si hay una pieza de middleware sincrónico, entonces Django debe usar un hilo por solicitud para emular de forma segura un entorno sincrónico para él.

Middleware can be built to support both sync and async contexts. Some of Django’s middleware is built like this, but not all. To see what middleware Django has to adapt for, you can turn on debug logging for the `django.request` logger and look for log messages about «Asynchronous handler adapted for middleware …».

Tanto en el modo ASGI como en el WSGI, aún puede utilizar de forma segura el soporte asincrónico para ejecutar código de forma simultánea en lugar de en serie. Esto es especialmente útil cuando se trata de APIs externas o almacenes de datos.

If you want to call a part of Django that is still synchronous, you will need to wrap it in a `sync_to_async()` call. For example:

    from asgiref.sync import sync_to_async

    results = await sync_to_async(sync_function, thread_sensitive=True)(pk=123)

If you accidentally try to call a part of Django that is synchronous-only from an async view, you will trigger Django’s asynchronous safety protection to protect your data from corruption.

### Decoradores

Los siguientes decoradores pueden ser usados tanto con funciones de vistas síncronas, como asíncronas:

- `cache_control()`

- `never_cache()`

- `no_append_slash()`

- `csp_override()`

- `csp_report_only_override()`

- `csrf_exempt()`

- `csrf_protect()`

- `ensure_csrf_cookie()`

- `requires_csrf_token()`

- `sensitive_variables()`

- `sensitive_post_parameters()`

- `gzip_page()`

- `condition()`

- `conditional_page()`

- `etag()`

- `last_modified()`

- `require_http_methods()`

- `require_GET()`

- `require_POST()`

- `require_safe()`

- `vary_on_cookie()`

- `vary_on_headers()`

- `xframe_options_deny()`

- `xframe_options_sameorigin()`

- `xframe_options_exempt()`

Por ejemplo:

    from django.views.decorators.cache import never_cache

    @never_cache
    def my_sync_view(request): ...

    @never_cache
    async def my_async_view(request): ...

### Consultas y ORM

Con algunas excepciones, Django también puede ejecutar consultas ORM de manera asíncrona:

    async for author in Author.objects.filter(name__startswith="A"):
        book = await author.books.afirst()

Notas detalladas se pueden encontrar en Asynchronous queries, pero en resumen:

- Todas los métodos de `QuerySet` que provocan una consulta SQL tienen una variante asíncrona con el prefijo `a`.

- `async for` is supported on all QuerySets (including the output of `values()` and `values_list()`.)

Django also supports some asynchronous model methods that use the database:

    async def make_book(*args, **kwargs):
        book = Book(...)
        await book.asave(using="secondary")

    async def make_book_with_tags(tags, *args, **kwargs):
        book = await Book.objects.acreate(...)
        await book.tags.aset(tags)

Transactions do not yet work in async mode. If you have a piece of code that needs transactions behavior, we recommend you write that piece as a single synchronous function and call it using `sync_to_async()`.

Persistent database connections, set via the `CONN_MAX_AGE` setting, should also be disabled in async mode. Instead, use your database backend’s built-in connection pooling if available, or investigate a third-party connection pooling option if required.

### Rendimiento

When running in a mode that does not match the view (e.g. an async view under WSGI, or a traditional sync view under ASGI), Django must emulate the other call style to allow your code to run. This context-switch causes a small performance penalty of around a millisecond.

This is also true of middleware. Django will attempt to minimize the number of context-switches between sync and async. If you have an ASGI server, but all your middleware and views are synchronous, it will switch just once, before it enters the middleware stack.

However, if you put synchronous middleware between an ASGI server and an asynchronous view, it will have to switch into sync mode for the middleware and then back to async mode for the view. Django will also hold the sync thread open for middleware exception propagation. This may not be noticeable at first, but adding this penalty of one thread per request can remove any async performance advantage.

You should do your own performance testing to see what effect ASGI versus WSGI has on your code. In some cases, there may be a performance increase even for a purely synchronous codebase under ASGI because the request-handling code is still all running asynchronously. In general you will only want to enable ASGI mode if you have asynchronous code in your project.

### Handling disconnects

For long-lived requests, a client may disconnect before the view returns a response. In this case, an `asyncio.CancelledError` will be raised in the view. You can catch this error and handle it if you need to perform any cleanup:

    async def my_view(request):
        try:
            # Do some work
            ...
        except asyncio.CancelledError:
            # Handle disconnect
            raise

You can also handle client disconnects in streaming responses.

## Seguridad asíncrona

DJANGO_ALLOW_ASYNC_UNSAFE

Certain key parts of Django are not able to operate safely in an async environment, as they have global state that is not coroutine-aware. These parts of Django are classified as «async-unsafe», and are protected from execution in an async environment. The ORM is the main example, but there are other parts that are also protected in this way.

If you try to run any of these parts from a thread where there is a running event loop, you will get a `SynchronousOnlyOperation` error. Note that you don’t have to be inside an async function directly to have this error occur. If you have called a sync function directly from an async function, without using `sync_to_async()` or similar, then it can also occur. This is because your code is still running in a thread with an active event loop, even though it may not be declared as async code.

If you encounter this error, you should fix your code to not call the offending code from an async context. Instead, write your code that talks to async-unsafe functions in its own, sync function, and call that using `asgiref.sync.sync_to_async()` (or any other way of running sync code in its own thread).

The async context can be imposed upon you by the environment in which you are running your Django code. For example, Jupyter notebooks and IPython interactive shells both transparently provide an active event loop so that it is easier to interact with asynchronous APIs.

If you’re using an IPython shell, you can disable this event loop by running:

    %autoawait off

as a command at the IPython prompt. This will allow you to run synchronous code without generating `SynchronousOnlyOperation` errors; however, you also won’t be able to `await` asynchronous APIs. To turn the event loop back on, run:

    %autoawait on

If you’re in an environment other than IPython (or you can’t turn off `autoawait` in IPython for some reason), you are certain there is no chance of your code being run concurrently, and you absolutely need to run your sync code from an async context, then you can disable the warning by setting the `DJANGO_ALLOW_ASYNC_UNSAFE` environment variable to any value.

Advertencia

If you enable this option and there is concurrent access to the async-unsafe parts of Django, you may suffer data loss or corruption. Be very careful and do not use this in production environments.

If you need to do this from within Python, do that with `os.environ`:

    import os

    os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

## Funciones adaptadoras asíncronas

It is necessary to adapt the calling style when calling sync code from an async context, or vice-versa. For this there are two adapter functions, from the `asgiref.sync` module: `async_to_sync()` and `sync_to_async()`. They are used to transition between the calling styles while preserving compatibility.

These adapter functions are widely used in Django. The asgiref package itself is part of the Django project, and it is automatically installed as a dependency when you install Django with `pip`.

### `async_to_sync()`

async_to_sync(async_function, force_new_loop=False)

Takes an async function and returns a sync function that wraps it. Can be used as either a direct wrapper or a decorator:

    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(): ...

The async function is run in the event loop for the current thread, if one is present. If there is no current event loop, a new event loop is spun up specifically for the single async invocation and shut down again once it completes. In either situation, the async function will execute on a different thread to the calling code.

Threadlocals and contextvars values are preserved across the boundary in both directions.

`async_to_sync()` is essentially a more powerful version of the `asyncio.run()` function in Python’s standard library. As well as ensuring threadlocals work, it also enables the `thread_sensitive` mode of `sync_to_async()` when that wrapper is used below it.

### `sync_to_async()`

sync_to_async(sync_function, thread_sensitive=True)

Takes a sync function and returns an async function that wraps it. Can be used as either a direct wrapper or a decorator:

    from asgiref.sync import sync_to_async

    async_function = sync_to_async(sync_function, thread_sensitive=False)
    async_function = sync_to_async(sensitive_sync_function, thread_sensitive=True)

    @sync_to_async
    def sync_function(): ...

Threadlocals and contextvars values are preserved across the boundary in both directions.

Sync functions tend to be written assuming they all run in the main thread, so `sync_to_async()` has two threading modes:

- `thread_sensitive=True` (the default): the sync function will run in the same thread as all other `thread_sensitive` functions. This will be the main thread, if the main thread is synchronous and you are using the `async_to_sync()` wrapper.

- `thread_sensitive=False`: the sync function will run in a brand new thread which is then closed once the invocation completes.

Advertencia

`asgiref` version 3.3.0 changed the default value of the `thread_sensitive` parameter to `True`. This is a safer default, and in many cases interacting with Django the correct value, but be sure to evaluate uses of `sync_to_async()` if updating `asgiref` from a prior version.

Thread-sensitive mode is quite special, and does a lot of work to run all functions in the same thread. Note, though, that it relies on usage of `async_to_sync()` above it in the stack to correctly run things on the main thread. If you use `asyncio.run()` or similar, it will fall back to running thread-sensitive functions in a single, shared thread, but this will not be the main thread.

The reason this is needed in Django is that many libraries, specifically database adapters, require that they are accessed in the same thread that they were created in. Also a lot of existing Django code assumes it all runs in the same thread, e.g. middleware adding things to a request for later use in views.

Rather than introduce potential compatibility issues with this code, we instead opted to add this mode so that all existing Django sync code runs in the same thread and thus is fully compatible with async mode. Note that sync code will always be in a different thread to any async code that is calling it, so you should avoid passing raw database handles or other thread-sensitive references around.

In practice this restriction means that you should not pass features of the database `connection` object when calling `sync_to_async()`. Doing so will trigger the thread safety checks:

    # DJANGO_SETTINGS_MODULE=settings.py python -m asyncio
    >>> import asyncio
    >>> from asgiref.sync import sync_to_async
    >>> from django.db import connection
    >>> # In an async context so you cannot use the database directly:
    >>> connection.cursor()
    django.core.exceptions.SynchronousOnlyOperation: You cannot call this from
    an async context - use a thread or sync_to_async.
    >>> # Nor can you pass resolved connection attributes across threads:
    >>> await sync_to_async(connection.cursor)()
    django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread
    can only be used in that same thread. The object with alias 'default' was
    created in thread id 4371465600 and this is thread id 6131478528.

Rather, you should encapsulate all database access within a helper function that can be called with `sync_to_async()` without relying on the connection object in the calling code.