diff --git a/graphene_django_extras/__init__.py b/graphene_django_extras/__init__.py index 8304968..f477c67 100644 --- a/graphene_django_extras/__init__.py +++ b/graphene_django_extras/__init__.py @@ -1,42 +1,42 @@ -# -*- coding: utf-8 -*- -from graphene.pyutils.version import get_version - -from .directives import all_directives -from .fields import DjangoObjectField, DjangoFilterListField, DjangoFilterPaginateListField, \ - DjangoListObjectField -from .middleware import ExtraGraphQLDirectiveMiddleware -from .mutation import DjangoSerializerMutation -from .paginations import LimitOffsetGraphqlPagination, PageGraphqlPagination, CursorGraphqlPagination -from .types import DjangoObjectType, DjangoInputObjectType, DjangoListObjectType, DjangoSerializerType - -VERSION = (0, 3, 8, 'beta', '8') - -__version__ = get_version(VERSION) - -__all__ = ( - '__version__', - - # FIELDS - 'DjangoObjectField', - 'DjangoFilterListField', - 'DjangoFilterPaginateListField', - 'DjangoListObjectField', - - # MUTATIONS - 'DjangoSerializerMutation', - - # PAGINATIONS - 'LimitOffsetGraphqlPagination', - 'PageGraphqlPagination', - # 'CursorGraphqlPagination', # Not implemented yet - - # TYPES - 'DjangoObjectType', - 'DjangoListObjectType', - 'DjangoInputObjectType', - 'DjangoSerializerType', - - # DIRECTIVES - 'all_directives', - 'ExtraGraphQLDirectiveMiddleware' -) +# -*- coding: utf-8 -*- +from graphene.pyutils.version import get_version + +from .directives import all_directives +from .fields import DjangoObjectField, DjangoFilterListField, DjangoFilterPaginateListField, \ + DjangoListObjectField +from .middleware import ExtraGraphQLDirectiveMiddleware +from .mutation import DjangoSerializerMutation +from .paginations import LimitOffsetGraphqlPagination, PageGraphqlPagination, CursorGraphqlPagination +from .types import DjangoObjectType, DjangoInputObjectType, DjangoListObjectType, DjangoSerializerType + +VERSION = (0, 3, 8, 'final', '') + +__version__ = get_version(VERSION) + +__all__ = ( + '__version__', + + # FIELDS + 'DjangoObjectField', + 'DjangoFilterListField', + 'DjangoFilterPaginateListField', + 'DjangoListObjectField', + + # MUTATIONS + 'DjangoSerializerMutation', + + # PAGINATIONS + 'LimitOffsetGraphqlPagination', + 'PageGraphqlPagination', + # 'CursorGraphqlPagination', # Not implemented yet + + # TYPES + 'DjangoObjectType', + 'DjangoListObjectType', + 'DjangoInputObjectType', + 'DjangoSerializerType', + + # DIRECTIVES + 'all_directives', + 'ExtraGraphQLDirectiveMiddleware' +) diff --git a/graphene_django_extras/fields.py b/graphene_django_extras/fields.py index 70e27b1..544d5f2 100644 --- a/graphene_django_extras/fields.py +++ b/graphene_django_extras/fields.py @@ -1,268 +1,268 @@ -# -*- coding: utf-8 -*- -import operator -from functools import partial - -from graphene import Field, List, ID, Argument -from graphene.types.structures import Structure -from graphene_django.filter.utils import get_filtering_args_from_filterset -from graphene_django.utils import maybe_queryset, is_valid_django_model, DJANGO_FILTER_INSTALLED -from graphene_django_extras.settings import graphql_api_settings - -from graphene_django_extras.filters.filter import get_filterset_class -from .base_types import DjangoListObjectBase -from .paginations.pagination import BaseDjangoGraphqlPagination -from .utils import get_extra_filters, queryset_factory, get_related_fields, find_field - - -# *********************************************** # -# *********** FIELD FOR SINGLE OBJECT *********** # -# *********************************************** # -class DjangoObjectField(Field): - def __init__(self, _type, *args, **kwargs): - kwargs['id'] = ID(required=True, description='Django object unique identification field') - - super(DjangoObjectField, self).__init__(_type, *args, **kwargs) - - @property - def model(self): - return self.type._meta.node._meta.model - - @staticmethod - def object_resolver(manager, root, info, **kwargs): - id = kwargs.pop('id', None) - - try: - return manager.get_queryset().get(pk=id) - except manager.model.DoesNotExist: - return None - - def get_resolver(self, parent_resolver): - return partial( - self.object_resolver, - self.type._meta.model._default_manager - ) - - -# *********************************************** # -# *************** FIELDS FOR LIST *************** # -# *********************************************** # -class DjangoFilterListField(Field): - - def __init__(self, _type, fields=None, extra_filter_meta=None, - filterset_class=None, *args, **kwargs): - - if DJANGO_FILTER_INSTALLED: - _fields = _type._meta.filter_fields - _model = _type._meta.model - - self.fields = fields or _fields - meta = dict(model=_model, fields=self.fields) - if extra_filter_meta: - meta.update(extra_filter_meta) - filterset_class = filterset_class or _type._meta.filterset_class - self.filterset_class = get_filterset_class(filterset_class, **meta) - self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) - kwargs.setdefault('args', {}) - kwargs['args'].update(self.filtering_args) - - if 'id' not in kwargs['args'].keys(): - self.filtering_args.update({'id': Argument(ID, - description='Django object unique identification field')}) - kwargs['args'].update({ - 'id': Argument(ID, description='Django object unique identification field') - }) - - if not kwargs.get('description', None): - kwargs['description'] = '{} list'.format( - _type._meta.model.__name__ - ) - - super(DjangoFilterListField, self).__init__( - List(_type), *args, **kwargs - ) - - @property - def model(self): - return self.type.of_type._meta.node._meta.model - - @staticmethod - def list_resolver(manager, filterset_class, filtering_args, root, info, **kwargs): - qs = None - field = None - - if root and is_valid_django_model(root._meta.model): - available_related_fields = get_related_fields(root._meta.model) - field = find_field( - info.field_asts[0], available_related_fields - ) - filter_kwargs = { - k: v for k, v in kwargs.items() if k in filtering_args - } - - if field is not None: - try: - if filter_kwargs: - qs = operator.attrgetter( - '{}.filter'.format( - getattr(field, 'related_name', None) or field.name) - )(root)(**filter_kwargs) - else: - qs = operator.attrgetter( - '{}.all'.format( - getattr(field, 'related_name', None) or field.name) - )(root)() - except AttributeError: - qs = None - - if qs is None: - qs = queryset_factory(manager, info.field_asts, info.fragments, **kwargs) - qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs - - if root and is_valid_django_model(root._meta.model): - extra_filters = get_extra_filters(root, manager.model) - qs = qs.filter(**extra_filters) - - return maybe_queryset(qs) - - def get_resolver(self, parent_resolver): - temp = self.type - while isinstance(temp, Structure): - temp = temp.of_type - return partial( - self.list_resolver, - temp._meta.model._default_manager, - self.filterset_class, - self.filtering_args - ) - - -class DjangoFilterPaginateListField(Field): - - def __init__(self, _type, pagination=None, fields=None, extra_filter_meta=None, - filterset_class=None, *args, **kwargs): - - _fields = _type._meta.filter_fields - _model = _type._meta.model - - self.fields = fields or _fields - meta = dict(model=_model, fields=self.fields) - if extra_filter_meta: - meta.update(extra_filter_meta) - - filterset_class = filterset_class or _type._meta.filterset_class - self.filterset_class = get_filterset_class(filterset_class, **meta) - self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) - kwargs.setdefault('args', {}) - kwargs['args'].update(self.filtering_args) - - if 'id' not in kwargs['args'].keys(): - self.filtering_args.update({'id': Argument(ID, description='Django object unique identification field')}) - kwargs['args'].update({'id': Argument(ID, description='Django object unique identification field')}) - - pagination = pagination or graphql_api_settings.DEFAULT_PAGINATION_CLASS() - - if pagination is not None: - assert isinstance(pagination, BaseDjangoGraphqlPagination), ( - 'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".' - ).format(pagination) - - pagination_kwargs = pagination.to_graphql_fields() - - self.pagination = pagination - kwargs.update(**pagination_kwargs) - - if not kwargs.get('description', None): - kwargs['description'] = '{} list'.format(_type._meta.model.__name__) - - super(DjangoFilterPaginateListField, self).__init__(List(_type), *args, **kwargs) - - @property - def model(self): - return self.type.of_type._meta.node._meta.model - - def get_queryset(self, manager, info, **kwargs): - return queryset_factory(manager, info.field_asts, info.fragments, **kwargs) - - def list_resolver(self, manager, filterset_class, filtering_args, - root, info, **kwargs): - filter_kwargs = {k: v for k, v in kwargs.items() if k in filtering_args} - qs = self.get_queryset(manager, info, **kwargs) - qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs - - if root and is_valid_django_model(root._meta.model): - extra_filters = get_extra_filters(root, manager.model) - qs = qs.filter(**extra_filters) - - if getattr(self, 'pagination', None): - qs = self.pagination.paginate_queryset(qs, **kwargs) - - return maybe_queryset(qs) - - def get_resolver(self, parent_resolver): - temp = self.type - while isinstance(temp, Structure): - temp = temp.of_type - return partial( - self.list_resolver, - temp._meta.model._default_manager, - self.filterset_class, - self.filtering_args - ) - - -class DjangoListObjectField(Field): - - def __init__(self, _type, fields=None, extra_filter_meta=None, filterset_class=None, *args, **kwargs): - - if DJANGO_FILTER_INSTALLED: - _fields = _type._meta.filter_fields - _model = _type._meta.model - - self.fields = fields or _fields - - meta = dict(model=_model, fields=self.fields) - if extra_filter_meta: - meta.update(extra_filter_meta) - - filterset_class = filterset_class or _type._meta.filterset_class - self.filterset_class = get_filterset_class(filterset_class, **meta) - self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) - kwargs.setdefault('args', {}) - kwargs['args'].update(self.filtering_args) - - if 'id' not in kwargs['args'].keys(): - id_description = 'Django object unique identification field' - self.filtering_args.update({'id': Argument(ID, description=id_description)}) - kwargs['args'].update({'id': Argument(ID, description=id_description)}) - - if not kwargs.get('description', None): - kwargs['description'] = '{} list'.format(_type._meta.model.__name__) - - super(DjangoListObjectField, self).__init__(_type, *args, **kwargs) - - @property - def model(self): - return self.type._meta.model - - def list_resolver(self, manager, filterset_class, filtering_args, root, info, **kwargs): - - qs = queryset_factory(manager, info.field_asts, info.fragments, **kwargs) - - filter_kwargs = {k: v for k, v in kwargs.items() if k in filtering_args} - - qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs - count = qs.count() - - return DjangoListObjectBase( - count=count, - results=maybe_queryset(qs), - results_field_name=self.type._meta.results_field_name - ) - - def get_resolver(self, parent_resolver): - return partial( - self.list_resolver, - self.type._meta.model._default_manager, - self.filterset_class, - self.filtering_args - ) +# -*- coding: utf-8 -*- +import operator +from functools import partial + +from graphene import Field, List, ID, Argument +from graphene.types.structures import Structure +from graphene_django.filter.utils import get_filtering_args_from_filterset +from graphene_django.utils import maybe_queryset, is_valid_django_model, DJANGO_FILTER_INSTALLED +from graphene_django_extras.settings import graphql_api_settings + +from graphene_django_extras.filters.filter import get_filterset_class +from .base_types import DjangoListObjectBase +from .paginations.pagination import BaseDjangoGraphqlPagination +from .utils import get_extra_filters, queryset_factory, get_related_fields, find_field + + +# *********************************************** # +# *********** FIELD FOR SINGLE OBJECT *********** # +# *********************************************** # +class DjangoObjectField(Field): + def __init__(self, _type, *args, **kwargs): + kwargs['id'] = ID(required=True, description='Django object unique identification field') + + super(DjangoObjectField, self).__init__(_type, *args, **kwargs) + + @property + def model(self): + return self.type._meta.node._meta.model + + @staticmethod + def object_resolver(manager, root, info, **kwargs): + id = kwargs.pop('id', None) + + try: + return manager.get_queryset().get(pk=id) + except manager.model.DoesNotExist: + return None + + def get_resolver(self, parent_resolver): + return partial( + self.object_resolver, + self.type._meta.model._default_manager + ) + + +# *********************************************** # +# *************** FIELDS FOR LIST *************** # +# *********************************************** # +class DjangoFilterListField(Field): + + def __init__(self, _type, fields=None, extra_filter_meta=None, + filterset_class=None, *args, **kwargs): + + if DJANGO_FILTER_INSTALLED: + _fields = _type._meta.filter_fields + _model = _type._meta.model + + self.fields = fields or _fields + meta = dict(model=_model, fields=self.fields) + if extra_filter_meta: + meta.update(extra_filter_meta) + filterset_class = filterset_class or _type._meta.filterset_class + self.filterset_class = get_filterset_class(filterset_class, **meta) + self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) + kwargs.setdefault('args', {}) + kwargs['args'].update(self.filtering_args) + + if 'id' not in kwargs['args'].keys(): + self.filtering_args.update({'id': Argument(ID, + description='Django object unique identification field')}) + kwargs['args'].update({ + 'id': Argument(ID, description='Django object unique identification field') + }) + + if not kwargs.get('description', None): + kwargs['description'] = '{} list'.format( + _type._meta.model.__name__ + ) + + super(DjangoFilterListField, self).__init__( + List(_type), *args, **kwargs + ) + + @property + def model(self): + return self.type.of_type._meta.node._meta.model + + @staticmethod + def list_resolver(manager, filterset_class, filtering_args, root, info, **kwargs): + qs = None + field = None + + if root and is_valid_django_model(root._meta.model): + available_related_fields = get_related_fields(root._meta.model) + field = find_field( + info.field_asts[0], available_related_fields + ) + filter_kwargs = { + k: v for k, v in kwargs.items() if k in filtering_args + } + + if field is not None: + try: + if filter_kwargs: + qs = operator.attrgetter( + '{}.filter'.format( + getattr(field, 'related_name', None) or field.name) + )(root)(**filter_kwargs) + else: + qs = operator.attrgetter( + '{}.all'.format( + getattr(field, 'related_name', None) or field.name) + )(root)() + except AttributeError: + qs = None + + if qs is None: + qs = queryset_factory(manager, info.field_asts, info.fragments, **kwargs) + qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs + + if root and is_valid_django_model(root._meta.model): + extra_filters = get_extra_filters(root, manager.model) + qs = qs.filter(**extra_filters) + + return maybe_queryset(qs) + + def get_resolver(self, parent_resolver): + current_type = self.type + while isinstance(current_type, Structure): + current_type = current_type.of_type + return partial( + self.list_resolver, + current_type._meta.model._default_manager, + self.filterset_class, + self.filtering_args + ) + + +class DjangoFilterPaginateListField(Field): + + def __init__(self, _type, pagination=None, fields=None, extra_filter_meta=None, + filterset_class=None, *args, **kwargs): + + _fields = _type._meta.filter_fields + _model = _type._meta.model + + self.fields = fields or _fields + meta = dict(model=_model, fields=self.fields) + if extra_filter_meta: + meta.update(extra_filter_meta) + + filterset_class = filterset_class or _type._meta.filterset_class + self.filterset_class = get_filterset_class(filterset_class, **meta) + self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) + kwargs.setdefault('args', {}) + kwargs['args'].update(self.filtering_args) + + if 'id' not in kwargs['args'].keys(): + self.filtering_args.update({'id': Argument(ID, description='Django object unique identification field')}) + kwargs['args'].update({'id': Argument(ID, description='Django object unique identification field')}) + + pagination = pagination or graphql_api_settings.DEFAULT_PAGINATION_CLASS() + + if pagination is not None: + assert isinstance(pagination, BaseDjangoGraphqlPagination), ( + 'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".' + ).format(pagination) + + pagination_kwargs = pagination.to_graphql_fields() + + self.pagination = pagination + kwargs.update(**pagination_kwargs) + + if not kwargs.get('description', None): + kwargs['description'] = '{} list'.format(_type._meta.model.__name__) + + super(DjangoFilterPaginateListField, self).__init__(List(_type), *args, **kwargs) + + @property + def model(self): + return self.type.of_type._meta.node._meta.model + + def get_queryset(self, manager, info, **kwargs): + return queryset_factory(manager, info.field_asts, info.fragments, **kwargs) + + def list_resolver(self, manager, filterset_class, filtering_args, + root, info, **kwargs): + filter_kwargs = {k: v for k, v in kwargs.items() if k in filtering_args} + qs = self.get_queryset(manager, info, **kwargs) + qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs + + if root and is_valid_django_model(root._meta.model): + extra_filters = get_extra_filters(root, manager.model) + qs = qs.filter(**extra_filters) + + if getattr(self, 'pagination', None): + qs = self.pagination.paginate_queryset(qs, **kwargs) + + return maybe_queryset(qs) + + def get_resolver(self, parent_resolver): + current_type = self.type + while isinstance(current_type, Structure): + current_type = current_type.of_type + return partial( + self.list_resolver, + current_type._meta.model._default_manager, + self.filterset_class, + self.filtering_args + ) + + +class DjangoListObjectField(Field): + + def __init__(self, _type, fields=None, extra_filter_meta=None, filterset_class=None, *args, **kwargs): + + if DJANGO_FILTER_INSTALLED: + _fields = _type._meta.filter_fields + _model = _type._meta.model + + self.fields = fields or _fields + + meta = dict(model=_model, fields=self.fields) + if extra_filter_meta: + meta.update(extra_filter_meta) + + filterset_class = filterset_class or _type._meta.filterset_class + self.filterset_class = get_filterset_class(filterset_class, **meta) + self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type) + kwargs.setdefault('args', {}) + kwargs['args'].update(self.filtering_args) + + if 'id' not in kwargs['args'].keys(): + id_description = 'Django object unique identification field' + self.filtering_args.update({'id': Argument(ID, description=id_description)}) + kwargs['args'].update({'id': Argument(ID, description=id_description)}) + + if not kwargs.get('description', None): + kwargs['description'] = '{} list'.format(_type._meta.model.__name__) + + super(DjangoListObjectField, self).__init__(_type, *args, **kwargs) + + @property + def model(self): + return self.type._meta.model + + def list_resolver(self, manager, filterset_class, filtering_args, root, info, **kwargs): + + qs = queryset_factory(manager, info.field_asts, info.fragments, **kwargs) + + filter_kwargs = {k: v for k, v in kwargs.items() if k in filtering_args} + + qs = filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs + count = qs.count() + + return DjangoListObjectBase( + count=count, + results=maybe_queryset(qs), + results_field_name=self.type._meta.results_field_name + ) + + def get_resolver(self, parent_resolver): + return partial( + self.list_resolver, + self.type._meta.model._default_manager, + self.filterset_class, + self.filtering_args + ) diff --git a/graphene_django_extras/views.py b/graphene_django_extras/views.py index b8f998e..743f773 100644 --- a/graphene_django_extras/views.py +++ b/graphene_django_extras/views.py @@ -20,7 +20,6 @@ class ExtraGraphQLView(GraphQLView, APIView): - def get_operation_ast(self, request): data = self.parse_body(request) query = request.GET.get('query') or data.get('query') diff --git a/setup.py b/setup.py index 316abe1..58a271e 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def get_packages(): url='https://github.com/eamigo86/graphene-django-extras', author='Ernesto Perez Amigo', - author_email='eamigo@nauta.cu', + author_email='eamigop86@gmail.com', license='MIT',