Skip to main content

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

  1. Define the dataloaders
from strawberry_django_dataloaders import dataloaders

class ColorPKDataLoader(dataloaders.BasicPKDataLoader):
    model = models.Color


class FruitPlantPKDataLoader(dataloaders.BasicPKDataLoader):
    model = models.FruitPlant
  1. 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

  1. 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
  1. 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

Known issues/shortcomings

  • Many-to-many relation is currently not supported.

Metadata

Release files for strawberry-django-dataloaders 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for strawberry-django-dataloaders 0.2.0
File Size Uploaded
strawberry_django_dataloaders-0.2.0.tar.gz 8.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for strawberry-django-dataloaders 0.2.0
File Interpreter ABI Platform
strawberry_django_dataloaders-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 18.7 kB

Release files / strawberry_django_dataloaders-0.2.0.tar.gz

Download URL strawberry_django_dataloaders-0.2.0.tar.gz
Size 8.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f76c47c58065fe449b88d0913332ae91e919f60ef9d57ebca2f8ebcb62d7c666
BLAKE2b-256 checksum
How to use checksums
47590e87b6838b165a15b3246ebb49581ae08f323f5f2a308501febd0d4597ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.7.0 CPython/3.10.13 Linux/6.2.0-1015-azure

Release files / strawberry_django_dataloaders-0.2.0-py3-none-any.whl

Download URL strawberry_django_dataloaders-0.2.0-py3-none-any.whl
Size 10.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0a47f61115a3596120e70d5a79cf936b55b20c5472c6b5bad59e0dc7456bc379
BLAKE2b-256 checksum
How to use checksums
478cdf5c21509b839d41fe555fb378f682d907b4e5b058639e01d235b3eeff5e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.7.0 CPython/3.10.13 Linux/6.2.0-1015-azure

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page