Metadata-Version: 2.1
Name: graphene-django-optimizer
Version: 0.8.0
Summary: Optimize database access inside graphene queries.
Home-page: https://github.com/tfoxy/graphene-django-optimizer
Author: Tomás Fox
Author-email: tomas.c.fox@gmail.com
License: MIT
Description: # graphene-django-optimizer
        
        [![build status](https://img.shields.io/travis/tfoxy/graphene-django-optimizer.svg)](https://travis-ci.org/tfoxy/graphene-django-optimizer)
        [![coverage](https://img.shields.io/codecov/c/github/tfoxy/graphene-django-optimizer.svg)](https://codecov.io/gh/tfoxy/graphene-django-optimizer)
        [![PyPI version](https://img.shields.io/pypi/v/graphene-django-optimizer.svg)](https://pypi.org/project/graphene-django-optimizer/)
        ![python version](https://img.shields.io/pypi/pyversions/graphene-django-optimizer.svg)
        ![django version](https://img.shields.io/pypi/djversions/graphene-django-optimizer.svg)
        
        Optimize queries executed by [graphene-django](https://github.com/graphql-python/graphene-django) automatically, using [`select_related`](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#select-related), [`prefetch_related`](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-related) and [`only`](https://docs.djangoproject.com/en/2.0/ref/models/querysets/#only) methods of Django QuerySet.
        
        
        ## Install
        
        ```bash
        pip install graphene-django-optimizer
        ```
        
        
        ## Usage
        
        Having the following schema based on [the tutorial of graphene-django](http://docs.graphene-python.org/projects/django/en/latest/tutorial-plain/#hello-graphql-schema-and-object-types) (notice the use of `gql_optimizer`)
        
        ```py
        # 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(object):
            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:
        
        ```graphql
        {
          all_ingredients {
            id
            name
            category {
                id
                name
            }
          }
        }
        ```
        
        ```py
        # optimized queryset:
        ingredients = (
            Ingredient.objects
            .select_related('category')
            .only('id', 'name', 'category__id', 'category__name')
        )
        ```
        
        Fetching all the categories with the related ingredients:
        
        ```graphql
        {
          all_categories {
            id
            name
            ingredients {
                id
                name
            }
          }
        }
        ```
        
        ```py
        # 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:
        
        ```py
        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:
        
        ```py
        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.
        
        ```py
        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:
        
        ```py
        
        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)
        ```
Keywords: graphene django optimizer optimize graphql query prefetch select related
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Framework :: Django
Classifier: Framework :: Django :: 1.11
Classifier: Framework :: Django :: 2.0
Classifier: Framework :: Django :: 2.1
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Description-Content-Type: text/markdown
