-
Notifications
You must be signed in to change notification settings - Fork 44
Description
** 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.datainternally callsto_representation(), which fetches data from the Django ORM.- Since Django ORM does not support async execution natively, accessing
.datainside 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.adatais available (async-aware serialization), it is awaited normally. - If
serializer.datais used (which is synchronous), it is executed safely insidesync_to_async().
🎯 Expected Results After the Fix
- ✅ No more
SynchronousOnlyOperationerrors. - ✅ 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,SynchronousOnlyOperationoccurs due toserializer.databeing accessed synchronously. This fix wraps.datainsidesync_to_asyncinget_data(), ensuring safe execution inside an async context.
📌 Steps to Reproduce:
- Use an async ViewSet that inherits from
ModelViewSetin ADRF. - Fetch a queryset using
alist(). - 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? 🚀