Skip to content

Issue in ADRF Causing SynchronousOnlyOperation in Django 5+ #56

@chafikblm

Description

@chafikblm

** Fix Issue in ADRF Causing SynchronousOnlyOperation in Django **

🚨 Issue Description

In Async Django projects using ADRF (Async Django Rest Framework), developers may encounter the following error when using alist() inside an async view:

django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

This error occurs when serializing data in an async context, specifically in the get_data() function inside adrf/mixins.py. The issue is that serializer.data is synchronous and should not be directly accessed inside an async function.


🛠️ Cause of the Issue

The problem lies in the following original code in adrf/mixins.py:

async def get_data(serializer):
    """Use adata if the serializer supports it, data otherwise."""
    return await serializer.adata if hasattr(serializer, "adata") else serializer.data

📌 Why is this an issue?

  • serializer.data internally calls to_representation(), which fetches data from the Django ORM.
  • Since Django ORM does not support async execution natively, accessing .data inside an async context leads to SynchronousOnlyOperation.

✅ Fix: Wrap Synchronous Calls in sync_to_async

To resolve this issue, modify get_data() to ensure that serializer.data runs in a sync-to-async safe context:

from asgiref.sync import sync_to_async

async def get_data(serializer):
    """Use adata if the serializer supports it, data otherwise."""
    return await serializer.adata if hasattr(serializer, "adata") else await sync_to_async(lambda: serializer.data)()

🔍 How This Fix Works

  • If serializer.adata is available (async-aware serialization), it is awaited normally.
  • If serializer.data is used (which is synchronous), it is executed safely inside sync_to_async().

🎯 Expected Results After the Fix

  • No more SynchronousOnlyOperation errors.
  • Fully async-safe execution of alist(), ensuring Django ORM does not break inside async views.
  • Performance improvement by handling serialization in an async-friendly way.

📢 How to Report This to ADRF Repository

📌 Suggested Issue Title:
Fix SynchronousOnlyOperation in async serializers by wrapping .data with sync_to_async

📌 Suggested Description:

In ADRF, when calling .alist() in an async Django view, SynchronousOnlyOperation occurs due to serializer.data being accessed synchronously. This fix wraps .data inside sync_to_async in get_data(), ensuring safe execution inside an async context.

📌 Steps to Reproduce:

  1. Use an async ViewSet that inherits from ModelViewSet in ADRF.
  2. Fetch a queryset using alist().
  3. If the serializer does not have .adata, it falls back to .data, causing the error.

📌 Proposed Fix:
Modify get_data() inside adrf/mixins.py as follows:

async def get_data(serializer):
    """Use adata if the serializer supports it, data otherwise."""
    return await serializer.adata if hasattr(serializer, "adata") else await sync_to_async(lambda: serializer.data)()

📌 Impact:
This fix ensures full compatibility with Django 5+ and avoids unnecessary sync operations inside async views.


Would you like me to draft a full GitHub issue for you? 🚀

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions