Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue in ADRF Causing SynchronousOnlyOperation in Django 5+ #56

Open
chafikblm opened this issue Feb 2, 2025 · 1 comment
Open

Issue in ADRF Causing SynchronousOnlyOperation in Django 5+ #56

chafikblm opened this issue Feb 2, 2025 · 1 comment

Comments

@chafikblm
Copy link

chafikblm commented Feb 2, 2025

** 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? 🚀

@bartvanandel
Copy link

I can confirm that this does the trick. I hope your fix can be released soon!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants