strawberry-django-optimizer
Optimize queries executed by strawberry automatically,
using select_related
, prefetch_related
and only
methods of Django QuerySet.
This package is heavily based on graphene-django-optimizer which is intended for use with graphene-django.
Install
pip install strawberry-django-optimizer
Usage
Having the following models based on the strawberry-graphql-django docs:
# models.py
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=20)
color = models.ForeignKey('Color', blank=True, null=True,
related_name='fruits', on_delete=models.CASCADE)
class Color(models.Model):
name = models.CharField(max_length=20)
And the following schema:
# schema.py
import strawberry
from typing import List
from strawberry.django import auto
from strawberry_django_optimizer import optimized_django_field
from fruits import models
@strawberry.django.type(models.Fruit)
class Fruit:
id: auto
name: auto
color: 'Color'
@strawberry.django.type(models.Color)
class Color:
id: auto
name: auto
fruits: List[Fruit]
@strawberry.type
class Query:
fruits: List[Fruit] = optimized_django_field()
The following graphql query would cause n + 1 DB queries:
query Fruit {
fruits {
id
name
color {
id
name
}
}
}
Since optimized_django_field
was used instead of strawberry.django.field
the queryset is automatically optimized.
# optimized queryset:
Fruits.objects.select_related('color').only('id', 'name', 'color__id', 'color__name')
Reverse ForeignKey
relations also are automatically optimized with prefetch_related
:
query Colors {
colors {
id
name
fruits {
id
name
}
}
}
# optimized queryset:
Color.objects.only('id', 'name', 'color').prefetch_related(
Prefetch('fruits', queryset=Fruit.objects.only('id', 'name'))
)
Advanced usage
Use resolver_hint
for cases where only
, select_related
and prefetch_related
optimizations can't be inferred automatically.
To keep the only
optimization when using custom resolver functions, resolver_hints
must be used to declare all fields that are accessed
or the only
optimization will be disabled.
# schema.py
import strawberry
from strawberry.django import auto
from strawberry_django_optimizer import resolver_hints
from fruits import models
@strawberry.django.type(models.Fruit)
class Fruit:
id: auto
@resolver_hints(only=('name',))
@strawberry.field
def name_display(self) -> str:
return f'My name is: {self.name}'
If the resolver function accesses a related field you can add an optimization hint for select_related
:
# schema.py
import strawberry
from strawberry.django import auto
from strawberry_django_optimizer import resolver_hints
from fruits import models
@strawberry.django.type(models.Fruit)
class Fruit:
id: auto
@resolver_hints(
select_related=('color',),
only=('color__name',),
)
def color_display(self) -> str:
return f'My color is: {self.color.name}'
resolver_hint
Parameters for Parameter | Usage |
---|---|
model_field |
If the resolver returns a model field |
only |
Declare all fields that the resolver accesses |
select_related |
If the resolver uses related fields |
prefetch_reltaed |
If the resolver uses related fields |
Known issues (ToDo)
- Inline Fragments can't be optimized
- Interfaces and Unions are not supported