Describe the Bug
A queryset returned from a strawberry_django.field resolver is automatically optimized when the type is resolved as part of a query or mutation, but not when the exact same type is yielded from a subscription — there it silently N+1s.
Minimal example
# models
class Color(models.Model):
name = models.CharField(max_length=50)
class Fruit(models.Model):
name = models.CharField(max_length=50)
color = models.ForeignKey(Color, related_name="fruits", on_delete=models.CASCADE)
# types
@strawberry_django.type(Fruit)
class FruitType:
id: auto
name: auto
color: "ColorType"
@strawberry_django.type(Color)
class ColorType:
id: auto
name: auto
# subscription payload — same shape that works fine as a mutation payload
@strawberry.type
class FruitsChanged:
ids: strawberry.Private[list[int]]
@strawberry_django.field(graphql_type=list[FruitType])
def fruits(self) -> QuerySet[Fruit]:
return Fruit.objects.filter(id__in=self.ids)
@strawberry.type
class Subscription:
@strawberry.subscription
async def fruits_changed(self, info) -> AsyncGenerat
async for changed_ids in listen_for_changes(info):
yield FruitsChanged(ids=changed_ids)
subscription {
fruitsChanged {
fruits { name color { name } }
}
}
Expected: 1 query with select_related("color") (which is what happens if the same
payload type is returned from a query/mutation).
Actual: 1 query for fruits + 1 query per fruit for color - N+1
System Information
- Operating system: MacOS 26.5.1
- Python version: 3.12.8
- Strawberry version (if applicable): 0.319.0
Describe the Bug
A queryset returned from a
strawberry_django.fieldresolver is automatically optimized when the type is resolved as part of a query or mutation, but not when the exact same type is yielded from a subscription — there it silently N+1s.Minimal example
Expected: 1 query with
select_related("color")(which is what happens if the samepayload type is returned from a query/mutation).
Actual: 1 query for fruits + 1 query per fruit for
color- N+1System Information