#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.

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top