Skip to main content

graphene-django-optimizer

Optimize queries executed by graphene-django automatically, using select_related, prefetch_related and only methods of Django QuerySet.

Install

pip install graphene-django-optimizer

Usage

Having the following schema based on the tutorial of graphene-django (notice the use of gql_optimizer)

# cookbook/ingredients/schema.py
import graphene

from graphene_django.types import DjangoObjectType
import graphene_django_optimizer as gql_optimizer

from cookbook.ingredients.models import Category, Ingredient


class CategoryType(DjangoObjectType):
    class Meta:
        model = Category


class IngredientType(DjangoObjectType):
    class Meta:
        model = Ingredient


class Query(graphene.ObjectType):
    all_categories = graphene.List(CategoryType)
    all_ingredients = graphene.List(IngredientType)

    def resolve_all_categories(root, info):
        return gql_optimizer.query(Category.objects.all(), info)

    def resolve_all_ingredients(root, info):
        return gql_optimizer.query(Ingredient.objects.all(), info)

We will show some graphql queries and the queryset that will be executed.

Fetching all the ingredients with the related category:

{
  allIngredients {
    id
    name
    category {
        id
        name
    }
  }
}
# optimized queryset:
ingredients = (
    Ingredient.objects
    .select_related('category')
    .only('id', 'name', 'category__id', 'category__name')
)

Fetching all the categories with the related ingredients:

{
  allCategories {
    id
    name
    ingredients {
        id
        name
    }
  }
}
# optimized queryset:
categories = (
    Category.objects
    .only('id', 'name')
    .prefetch_related(Prefetch(
        'ingredients',
        queryset=Ingredient.objects.only('id', 'name'),
    ))
)

Advanced usage

Sometimes we need to have a custom resolver function. In those cases, the field can't be auto optimized. So we need to use gql_optimizer.resolver_hints decorator to indicate the optimizations.

If the resolver returns a model field, we can use the model_field argument:

import graphene
import graphene_django_optimizer as gql_optimizer


class ItemType(gql_optimizer.OptimizedDjangoObjectType):
    product = graphene.Field('ProductType')

    @gql_optimizer.resolver_hints(
        model_field='product',
    )
    def resolve_product(root, info):
        # check if user have permission for seeing the product
        if info.context.user.is_anonymous():
            return None
        return root.product

This will automatically optimize any subfield of product.

Now, if the resolver uses related fields, you can use the select_related argument:

import graphene
import graphene_django_optimizer as gql_optimizer


class ItemType(gql_optimizer.OptimizedDjangoObjectType):
    name = graphene.String()

    @gql_optimizer.resolver_hints(
        select_related=('product', 'shipping'),
        only=('product__name', 'shipping__name'),
    )
    def resolve_name(root, info):
        return '{} {}'.format(root.product.name, root.shipping.name)

Notice the usage of the type OptimizedDjangoObjectType, which enables optimization of any single node queries.

Finally, if your field has an argument for filtering results, you can use the prefetch_related argument with a function that returns a Prefetch instance as the value.

from django.db.models import Prefetch
import graphene
import graphene_django_optimizer as gql_optimizer


class CartType(gql_optimizer.OptimizedDjangoObjectType):
    items = graphene.List(
        'ItemType',
        product_id=graphene.ID(),
    )

    @gql_optimizer.resolver_hints(
        prefetch_related=lambda info, product_id: Prefetch(
            'items',
            queryset=gql_optimizer.query(Item.objects.filter(product_id=product_id), info),
            to_attr='gql_product_id_' + product_id,
        ),
    )
    def resolve_items(root, info, product_id):
        return getattr(root, 'gql_product_id_' + product_id)

With these hints, any field can be optimized.

Optimize with non model fields

Sometimes we need to have a custom non model fields. In those cases, the optimizer would not optimize with the Django .only() method. So if we still want to optimize with the .only() method, we need to use disable_abort_only option:

class IngredientType(gql_optimizer.OptimizedDjangoObjectType):
    calculated_calories = graphene.String()

    class Meta:
        model = Ingredient

    def resolve_calculated_calories(root, info):
        return get_calories_for_ingredient(root.id)


class Query(object):
    all_ingredients = graphene.List(IngredientType)

    def resolve_all_ingredients(root, info):
        return gql_optimizer.query(Ingredient.objects.all(), info, disable_abort_only=True)

Metadata

Release files for graphene-django-optimizer-reloaded 0.9.2

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

Source distribution (sdist)

Source distribution for graphene-django-optimizer-reloaded 0.9.2
File Size Uploaded
graphene_django_optimizer_reloaded-0.9.2.tar.gz 14.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for graphene-django-optimizer-reloaded 0.9.2
File Interpreter ABI Platform
graphene_django_optimizer_reloaded-0.9.2-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 24.3 kB

Release files / graphene_django_optimizer_reloaded-0.9.2.tar.gz

Download URL graphene_django_optimizer_reloaded-0.9.2.tar.gz
Size 14.2 kB
Tags Source
SHA-256 checksum
How to use checksums
488eb4a6a6ece6935027da4149c7a328c6dfc58ca40af7d4c00daa33884309a2
BLAKE2b-256 checksum
How to use checksums
9222024fff630701948e52b3398f5bec9bfd62d442f601d18671891a2af0c994
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.12.7

Release files / graphene_django_optimizer_reloaded-0.9.2-py2.py3-none-any.whl

Download URL graphene_django_optimizer_reloaded-0.9.2-py2.py3-none-any.whl
Size 10.2 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
10b9522487131b56ceeceda5379fb872341109f1a63b7186b3519b4b7a66620b
BLAKE2b-256 checksum
How to use checksums
2395e6fe3ea2750a29aea67386249e5cffee57a3a105aa40059a88638e25dd67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.12.7

Release history Release notifications | RSS feed

This release

0.9.2 This release

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