Add async support for ForwardManyToOne, ForwardOneToOne, and ReverseOneToOne queries

Hi @HappyDingning — Welcome, thanks for your post.

I’m going to cc @adamchainz and @andrewgodwin on this as they’ve both been involved related discussions.

Since the first discussions on adding async, lazy fetching of related objects has been an obvious sticking point. restaurant.place triggers a DB lookup standardly, and so (as you say) you need to wrap that in a function.

The first take here has always been that you should use prefetch_related() &co in order to fetch the related Place when first fetching the Restaurant, rather than using the lazy fetch. Beyond a very basic scale you want to be doing this anyway, so not adding async support here looks like encouraging best practice…

Then there’s a typing problem (and the indicated code-smell) with adding async support to the lazy fetch as you suggest:

place = await restaurant.place

Here the return type of the related attribute isn’t a(n optional) Place but that or an awaitable.

There was a similar discussion on the Django ticket #39102 about adding async support to the request.user lookup. We had a proof-of-concept there but went for a separate auser() method to keep the usage clear. The discussion there links to a Python typing issue that ruled out different typing depending on whether await was used or not: Have different methods! was the advice coming down from there.

As such I’m not sure that adding async support for lazy related object lookups is something that’s on the table.

Kind Regards,

Carlton