This works just fine and only performs one DB query:
qs = Blog.objects.filter(post=Subquery(
Post.objects.filter(blog=OuterRef("pk"))
.order_by("-date").values("pk")[:1]
))
for bt, pt in qs.values_list("title", "post__title"):
print(f"The latest post in {bt} is about {pt}")
However, how can I have Django construct Blog and Post objects out of such a queryset without needing additional queries? Something like the following:
for blog in qs.select_related("post"):
print(f"The latest post in {blog.title} is about {blog.post.title}")
Assume it’s not possible to reverse the queryset (Post.objects.select_related("blog")), because, for example, there are other related models that need the same treatment as Post.
Surprisingly, this works!
qs = Blog.objects.annotate(
latest_post=FilteredRelation(
"post",
condition=Q(
post=Subquery(
Post.objects.filter(blog=OuterRef("pk"))
.order_by("-seq")
.values("pk")[:1]
),
),
),
).select_related("latest_post")
for blog in qs:
print(f"The latest post in {blog.title} is about {blog.latest_post.title}")
This doesn’t actually require the condition to be unique:
for blog in Blog.objects.annotate(
some_post=FilteredRelation("post"),
).select_related("some_post"):
do_something(blog, blog.some_post)
# will happen multiple times for the same blog
# but blog.some_post will be different each time