Skip to content

Commit 69fa221

Browse files
authored
Add note about SynchronousOnlyOperation in Django's docs (#3936)
* Add note about SynchronousOnlyOperation in Django's docs * Improve text
1 parent 93584c9 commit 69fa221

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

docs/integrations/django.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,100 @@ urlpatterns = [
246246
You'd also need to add `strawberry_django` to the `INSTALLED_APPS` of your
247247
project, this is needed to provide the template for the GraphiQL interface.
248248

249+
## Important Note: Django ORM and Async Context
250+
251+
When using `AsyncGraphQLView`, you may encounter a `SynchronousOnlyOperation`
252+
error if your resolvers access Django's ORM directly:
253+
254+
```text
255+
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
256+
```
257+
258+
This occurs because Django's ORM is synchronous by default and cannot be called
259+
directly from async contexts like the `AsyncGraphQLView`. Here are two
260+
solutions:
261+
262+
### Solution 1: Use the async version of the ORM methods
263+
264+
Instead of using the standard version of the ORM methods, you can usually use an
265+
async version, for example, in addition to `get` Django also provides `aget`
266+
than can be used in an async context:
267+
268+
```python
269+
import strawberry
270+
from django.contrib.auth.models import User
271+
272+
273+
@strawberry.type
274+
class Query:
275+
@strawberry.field
276+
@staticmethod
277+
async def user_name(id: strawberry.ID) -> str:
278+
# Note: this is a simple example, you'd normally just return
279+
# a full user instead of making a resolver to get a user's name
280+
# by id. This is just to explain the async issues with Django :)
281+
282+
user = await User.objects.aget(id)
283+
# This would cause SynchronousOnlyOperation error:
284+
# user = User.objects.get(id)
285+
286+
return user.name
287+
```
288+
289+
You can find all the supported methods in the
290+
[Asynchronous support guide](https://docs.djangoproject.com/en/5.2/topics/async/)
291+
on Django's website.
292+
293+
### Solution 2: Use `sync_to_async`
294+
295+
While some ORM methods have an async equivalent, not all of them do, in that
296+
case you can wrap your ORM operations with Django's `sync_to_async`:
297+
298+
```python
299+
import strawberry
300+
from django.contrib.auth.models import User
301+
from asgiref.sync import sync_to_async
302+
303+
304+
@strawberry.type
305+
class Query:
306+
@strawberry.field
307+
async def users(self) -> list[str]:
308+
# This would cause SynchronousOnlyOperation error:
309+
# return [user.username for user in User.objects.all()]
310+
311+
# Correct way using sync_to_async:
312+
users = await sync_to_async(list)(User.objects.all())
313+
314+
return [user.username for user in users]
315+
```
316+
317+
### Solution 3: Use `strawberry_django` (Recommended)
318+
319+
The `strawberry_django` package automatically handles async/sync compatibility.
320+
Use `strawberry_django.field` instead of `strawberry.field`:
321+
322+
```python
323+
import strawberry_django
324+
from django.contrib.auth.models import User
325+
326+
327+
@strawberry_django.type(User)
328+
class UserType:
329+
username: str
330+
email: str
331+
332+
333+
@strawberry.type
334+
class Query:
335+
# This automatically works with both sync and async views
336+
users: list[UserType] = strawberry_django.field()
337+
```
338+
339+
We recommend using the `strawberry_django` package for Django ORM integration as
340+
it provides automatic async/sync compatibility and additional Django-specific
341+
features.
342+
249343
## Options
250344

251345
The `AsyncGraphQLView` accepts the following arguments:

0 commit comments

Comments
 (0)