Opened 42 minutes ago
#37343 new New feature
Use FETCH_ASYNC as the default fetch mode for async ORM queries (replace SynchronousOnlyOperation on implicit related fetches)
| Reported by: | Mykhailo Havelia | Owned by: | |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 6.1 |
| Severity: | Normal | Keywords: | async orm |
| Cc: | Mykhailo Havelia | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Description:
Django 6.1 added fetch modes (FETCH_ONE, FETCH_PEERS, FETCH_RAISE). I'd like to propose using them to improve the async ORM experience.
Problem
Async Django ORM doesn't support the active-record pattern for related objects. Accessing an unloaded relation triggers an implicit synchronous fetch:
book = await Book.objects.aget(pk=1) book.author.name # implicit FK fetch
Without select_related() / prefetch_related(), this raises SynchronousOnlyOperation. That error is confusing here: it describes the mechanism (a sync DB call inside an async context) rather than the actual mistake (accessing a relation that wasn't loaded). A developer new to async Django can't easily tell from it what to do next (or it can make a silent sync call if DJANGO_ALLOW_ASYNC_UNSAFE is true).
Proposal
When a query runs in async mode, default its fetch mode to FETCH_ASYNC instead of relying on the implicit-sync path. Accessing an unloaded field would then raise FieldFetchBlocked with a message pointing to the fix
FieldFetchBlocked: 'author' isn't fetched. Load it with select_related()/prefetch_related().
This turns a low-level error into an actionable ORM error, at the exact spot where the developer needs guidance.
Context
This came up in django-async-backend. We can hardcode a custom fetch function there to raise our own error, but it would be much better to have consistent behavior inside Django itself.