A set of tools for using dataloaders with Django and Strawberry GraphQL.
Project description
Dataloaders for Django and Strawberry
A set of tools for using dataloaders with Django and Strawberry without unnecessary boilerplate.
Installation
pip install strawberry-django-dataloaders
Usage & examples
This package provides 3 levels of generating dataloaders, each offering higher level of abstraction than the previous one.
View
In the graphql/
endpoint where you wish to use dataloaders, use (or subclass) DataloaderAsyncGraphQLView
.
This is necessary because created dataloaders are stored to the request context. This ensures that:
- fresh dataloader instances are created for each request
- a dataloader persists for the duration of the request
which are both important properties for loaded values caching.
from django.urls import path
from strawberry_django_dataloaders.views import DataloaderAsyncGraphQLView
urlpatterns = [
path('graphql/', DataloaderAsyncGraphQLView.as_view(schema=...)),
]
Models definition
Definition of models used in the examples.
from django.db import models
class Fruit(models.Model):
plant = models.OneToOneField("FruitPlant", ...)
color = models.ForeignKey("Color", ...)
varieties = models.ManyToManyField("FruitVariety", ..., related_name="fruits")
class FruitEater(models.Model):
favourite_fruit = models.ForeignKey("Fruit", ..., related_name="eaters")
Level 1: Simple dataloader
On the first level, we're defining and using different dataloader for each relationship.
One-to-one and Many-to-one relationship
- Define the dataloaders
from strawberry_django_dataloaders import dataloaders
class ColorPKDataLoader(dataloaders.BasicPKDataLoader):
model = models.Color
class FruitPlantPKDataLoader(dataloaders.BasicPKDataLoader):
model = models.FruitPlant
- Use them when defining the Strawberry type
@strawberry_django.type(models.Fruit)
class FruitType:
id: strawberry.auto
### ↓ HERE ↓ ###
@strawberry.field
async def color(self: "models.Fruit", info: "Info") -> ColorType | None:
return await dataloaders.ColorPKDataLoader(context=info.context).load(self.color_id)
@strawberry.field
async def plant(self: "models.Fruit", info: "Info") -> FruitPlantType | None:
return await dataloaders.FruitPlantPKDataLoader(context=info.context).load(self.plant_id)
One-to-many relationship
- Define the dataloader
from strawberry_django_dataloaders import dataloaders
class FruitEatersReverseFKDataLoader(dataloaders.BasicReverseFKDataLoader):
model = models.FruitEater
reverse_path = "favourite_fruit_id" # <-- is the "reverse" FK field from FruitEater to Fruit model
- Use it when defining the Strawberry type
@strawberry_django.type(models.Fruit)
class FruitType:
id: strawberry.auto
### ↓ HERE ↓ ###
@strawberry.field
async def eaters(self: "models.Fruit", info: "Info") -> list[FruitEaterType]:
return await dataloaders.FruitEatersReverseFKDataLoader(context=info.context).load(self.pk)
Level 2: Dataloader factories
When using the dataloader factories, we no longer need to define a dataloader for each relation.
from strawberry_django_dataloaders import factories
@strawberry_django.type(models.Fruit)
class FruitTypeDataLoaderFactories:
id: strawberry.auto
### ↓ ONE-TO-ONE AND MANY-TO-ONE DATALOADERS ↓ ###
@strawberry.field
async def color(self: "models.Fruit", info: "Info") -> ColorType | None:
loader = factories.PKDataLoaderFactory.get_loader_class("tests.Color")
return await loader(context=info.context).load(self.color_id)
@strawberry.field
async def plant(self: "models.Fruit", info: "Info") -> FruitPlantType | None:
loader = factories.PKDataLoaderFactory.get_loader_class("tests.FruitPlant")
return await loader(context=info.context).load(self.plant_id)
### ↓ ONE-TO-MANY DATALOADER ↓ ###
@strawberry.field
async def eaters(self: "models.Fruit", info: "Info") -> list[FruitEaterType]:
loader = factories.ReverseFKDataLoaderFactory.get_loader_class(
"tests.FruitEater",
reverse_path="favourite_fruit_id",
)
return await loader(context=info.context).load(self.color_id)
Level 3: Auto dataloader field
A field used in a similar fashion as native Django strawberry field, but it has auto-defined correct dataloader handler based on the field relationship.
from strawberry_django_dataloaders import fields
@strawberry_django.type(models.Fruit)
class FruitTypeAutoDataLoaderFields:
id: strawberry.auto
color: ColorType = fields.auto_dataloader_field()
plant: FruitPlantType = fields.auto_dataloader_field()
varieties: list[FruitVarietyType] = fields.auto_dataloader_field()
eaters: list[FruitEaterType] = fields.auto_dataloader_field()
Contributing
Pull requests for any improvements are welcome.
Poetry is used to manage dependencies. To get started follow these steps:
git clone https://github.com/VojtechPetru/strawberry-django-dataloaders
cd strawberry-django-dataloaders
poetry install
poetry run pytest
Pre commit
We have a configuration for pre-commit, to add the hook run the following command:
pre-commit install
Links
- Inspired and builds on top of a great article at: https://alexcleduc.com/posts/graphql-dataloader-composition/
- Repository: https://github.com/VojtechPetru/strawberry-django-dataloaders
- Issue tracker: https://github.com/VojtechPetru/strawberry-django-dataloaders/issues. In case of sensitive bugs (e.g. security vulnerabilities) please contact me at petru.vojtech@gmail.com directly.
Known issues/shortcomings
Many-to-many
relation is currently not supported.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file strawberry_django_dataloaders-0.2.0.tar.gz
.
File metadata
- Download URL: strawberry_django_dataloaders-0.2.0.tar.gz
- Upload date:
- Size: 8.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.0 CPython/3.10.13 Linux/6.2.0-1015-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | f76c47c58065fe449b88d0913332ae91e919f60ef9d57ebca2f8ebcb62d7c666 |
|
MD5 | 6d617731fcb4b182c87691ec44dd10e5 |
|
BLAKE2b-256 | 47590e87b6838b165a15b3246ebb49581ae08f323f5f2a308501febd0d4597ad |
File details
Details for the file strawberry_django_dataloaders-0.2.0-py3-none-any.whl
.
File metadata
- Download URL: strawberry_django_dataloaders-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.0 CPython/3.10.13 Linux/6.2.0-1015-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0a47f61115a3596120e70d5a79cf936b55b20c5472c6b5bad59e0dc7456bc379 |
|
MD5 | 2a8704d6b9a69e8b9d3ab53314c99341 |
|
BLAKE2b-256 | 478cdf5c21509b839d41fe555fb378f682d907b4e5b058639e01d235b3eeff5e |