%global _empty_manifest_terminate_build 0 Name: python-graphene-django-optimizer Version: 0.9.1 Release: 1 Summary: Optimize database access inside graphene queries. License: MIT URL: https://github.com/tfoxy/graphene-django-optimizer Source0: https://mirrors.nju.edu.cn/pypi/web/packages/96/00/361d61157e8e3abe70abf0d12c994adbee50acb60a790bddc3c05ce6fb9f/graphene-django-optimizer-0.9.1.tar.gz BuildArch: noarch %description # graphene-django-optimizer [![build status](https://img.shields.io/travis/tfoxy/graphene-django-optimizer.svg)](https://travis-ci.com/github/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 ``` *Note: If you are using Graphene V2, please install version `0.8`. v0.9 and forward will support only Graphene V3* ## 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(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: ```graphql { allIngredients { 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 { allCategories { 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) ``` %package -n python3-graphene-django-optimizer Summary: Optimize database access inside graphene queries. Provides: python-graphene-django-optimizer BuildRequires: python3-devel BuildRequires: python3-setuptools BuildRequires: python3-pip %description -n python3-graphene-django-optimizer # graphene-django-optimizer [![build status](https://img.shields.io/travis/tfoxy/graphene-django-optimizer.svg)](https://travis-ci.com/github/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 ``` *Note: If you are using Graphene V2, please install version `0.8`. v0.9 and forward will support only Graphene V3* ## 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(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: ```graphql { allIngredients { 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 { allCategories { 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) ``` %package help Summary: Development documents and examples for graphene-django-optimizer Provides: python3-graphene-django-optimizer-doc %description help # graphene-django-optimizer [![build status](https://img.shields.io/travis/tfoxy/graphene-django-optimizer.svg)](https://travis-ci.com/github/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 ``` *Note: If you are using Graphene V2, please install version `0.8`. v0.9 and forward will support only Graphene V3* ## 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(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: ```graphql { allIngredients { 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 { allCategories { 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) ``` %prep %autosetup -n graphene-django-optimizer-0.9.1 %build %py3_build %install %py3_install install -d -m755 %{buildroot}/%{_pkgdocdir} if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi pushd %{buildroot} if [ -d usr/lib ]; then find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/lib64 ]; then find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/bin ]; then find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst fi if [ -d usr/sbin ]; then find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst fi touch doclist.lst if [ -d usr/share/man ]; then find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst fi popd mv %{buildroot}/filelist.lst . mv %{buildroot}/doclist.lst . %files -n python3-graphene-django-optimizer -f filelist.lst %dir %{python3_sitelib}/* %files help -f doclist.lst %{_docdir}/* %changelog * Tue Apr 11 2023 Python_Bot - 0.9.1-1 - Package Spec generated