Skip to content

Commit

Permalink
Add queryset options to DjangoListObjectType Meta class for specify w…
Browse files Browse the repository at this point in the history
…anted model queryset.

Add AuthenticatedGraphQLView on graphene_django_extras.views for use
    'permission', 'authorization' and 'throttle' classes based on the DRF settings. Special thanks to
    [@jacobh](https://github.com/jacobh) for this [comment](graphql-python/graphene#249 (comment))
  • Loading branch information
Ernesto Perez Amigo committed Oct 24, 2017
1 parent c6236f9 commit 12dc8c8
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 21 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,15 @@ subscription{

## Change Log:

#### v0.1.0-alpha4:
1. Add queryset options to DjangoListObjectType Meta class for specify wanted model queryset.
2. Add AuthenticatedGraphQLView on graphene_django_extras.views for use
'permission', 'authorization' and 'throttle' classes based on the DRF settings. Special thanks to
[@jacobh](https://github.com/jacobh) for this [comment](https://github.com/graphql-python/graphene/issues/249#issuecomment-300068390)

#### v0.1.0-alpha3:
1. Fixed bug on subscriptions when not specified any field in "data" parameter to bean return on notification message.
1. Fixed bug on subscriptions when not specified any field in "data" parameter to bean return on notification
message.

#### v0.1.0-alpha2:
1. Fixed bug when subscribing to a given action (create, update pr delete).
Expand Down
9 changes: 8 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -484,10 +484,17 @@ For unsubscribe you must send a graphql subscription request like this:
Change Log:
-----------

**************
v0.1.0-alpha4:
**************
1. Add **queryset** options to **DjangoListObjectType** Meta class for specify wanted model queryset.
2. Add AuthenticatedGraphQLView on graphene_django_extras.views for use 'permission', 'authorization' and 'throttle' classes based on the DRF settings. Special thanks to `@jacobh <https://github.com/jacobh>`_ for this `comment <https://github.com/graphql-python/graphene/issues/249#issuecomment-300068390>`_.

**************
v0.1.0-alpha3:
**************
1. Fixed bug on subscriptions when not specified any field in "data" parameter to bean return on notification message.
1. Fixed bug on subscriptions when not specified any field in "data" parameter to bean return on
notification message.

**************
v0.1.0-alpha2:
Expand Down
2 changes: 1 addition & 1 deletion graphene_django_extras/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .types import DjangoObjectType, DjangoInputObjectType, DjangoListObjectType
from .subscriptions import *

VERSION = (0, 1, 0, 'alpha', '3')
VERSION = (0, 1, 0, 'alpha', '4')

__version__ = get_version(VERSION)

Expand Down
2 changes: 1 addition & 1 deletion graphene_django_extras/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,5 +230,5 @@ def list_resolver(self, manager, filterset_class, filtering_args, root, info, **
)

def get_resolver(self, parent_resolver):
return partial(self.list_resolver, self.type._meta.model._default_manager,
return partial(self.list_resolver, self.type._meta.queryset or self.type._meta.model._default_manager,
self.filterset_class, self.filtering_args)
3 changes: 1 addition & 2 deletions graphene_django_extras/subscriptions/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,5 @@ def serialize_data(self, instance):
data = self.get_serializer(instance).data
only_fields = hasattr(self.get_serializer_class().Meta, 'only_fields')
if only_fields:
if self.get_serializer_class().Meta.only_fields != ['all_fields']:
data = {k: v for k, v in data.items() if k in self.get_serializer_class().Meta.only_fields}
data = {k: v for k, v in data.items() if k in self.get_serializer_class().Meta.only_fields}
return data
3 changes: 1 addition & 2 deletions graphene_django_extras/subscriptions/subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ def __init_subclass_with_meta__(cls, mutation_class=None, stream=None, queryset=

serializer_fields = [(to_snake_case(field.strip('_')).upper(), to_snake_case(field))
for field in _meta.serializer_class.Meta.fields]
model_fields_enum = Enum('{}Fields'.format(mutation_class._meta.model.__name__),
serializer_fields + [('ALL_FIELDS', 'all_fields')],
model_fields_enum = Enum('{}Fields'.format(mutation_class._meta.model.__name__), serializer_fields,
description=_('Desired {} fields in subscription\'s notification. You can specify '
'"all_fields" value.').format(mutation_class._meta.model.__name__))

Expand Down
10 changes: 9 additions & 1 deletion graphene_django_extras/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from collections import OrderedDict

from django.db.models import QuerySet
from django.utils.functional import SimpleLazyObject
from django.utils.translation import ugettext_lazy as _
from graphene import Field, InputField, ObjectType, Int
Expand All @@ -23,6 +24,7 @@ class DjangoObjectOptions(BaseOptions):
input_fields = None
interfaces = ()
model = None
queryset = None
registry = None
connection = None
create_container = None
Expand Down Expand Up @@ -165,7 +167,7 @@ class Meta:
@classmethod
def __init_subclass_with_meta__(cls, model=None, results_field_name=None, pagination=None,
only_fields=(), exclude_fields=(), filter_fields=None,
interfaces=(), **options):
queryset=None, interfaces=(), **options):

assert is_valid_django_model(model), (
'You need to pass a valid Django Model in {}.Meta, received "{}".'
Expand All @@ -174,6 +176,11 @@ def __init_subclass_with_meta__(cls, model=None, results_field_name=None, pagina
if not DJANGO_FILTER_INSTALLED and filter_fields:
raise Exception("Can only set filter_fields if Django-Filter is installed")

assert isinstance(queryset, QuerySet) or queryset is None, (
'The attribute queryset in {} needs to be an instance of '
'Django model queryset, received "{}".'
).format(cls.__name__, queryset)

results_field_name = results_field_name or 'results'

baseType = get_global_registry().get_type_for_model(model)
Expand All @@ -200,6 +207,7 @@ def __init_subclass_with_meta__(cls, model=None, results_field_name=None, pagina

_meta = DjangoObjectOptions(cls)
_meta.model = model
_meta.queryset = queryset
_meta.baseType = baseType
_meta.results_field_name = results_field_name
_meta.filter_fields = filter_fields
Expand Down
16 changes: 4 additions & 12 deletions graphene_django_extras/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ def get_model_fields(model):
list(model._meta.local_many_to_many) +
list(model._meta.virtual_fields))
]
"""
local_fields = [
(field.name, field)
for field
in sorted(list(model._meta.fields) +
list(model._meta.local_many_to_many))
]
"""

# Make sure we don't duplicate local fields with "reverse" version
local_field_names = [field[0] for field in local_fields]
Expand Down Expand Up @@ -249,9 +241,9 @@ def queryset_factory(manager, fields_asts=None, fragments=None, **kwargs):
prefetch_related)

if select_related and prefetch_related:
return manager.select_related(*select_related).prefetch_related(*prefetch_related)
return _get_queryset(manager.select_related(*select_related).prefetch_related(*prefetch_related))
elif not select_related and prefetch_related:
return manager.prefetch_related(*prefetch_related)
return _get_queryset(manager.prefetch_related(*prefetch_related))
elif select_related and not prefetch_related:
return manager.select_related(*select_related)
return manager.get_queryset()
return _get_queryset(manager.select_related(*select_related))
return _get_queryset(manager)
28 changes: 28 additions & 0 deletions graphene_django_extras/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from graphene_django.views import GraphQLView
from rest_framework.decorators import (authentication_classes, permission_classes, api_view, throttle_classes)
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.settings import api_settings
from rest_framework.views import APIView


class AuthenticatedGraphQLView(GraphQLView, APIView):
"""
Extra Graphql view that use 'permission', 'authorization' and 'throttle' classes based on the DRF settings.
Thanks to @jacobh in (https://github.com/graphql-python/graphene/issues/249#issuecomment-300068390)
"""
def parse_body(self, request):
if isinstance(request, Request):
return request.data
return super(AuthenticatedGraphQLView, self).parse_body(request)

@classmethod
def as_view(cls, *args, **kwargs):
view = super(AuthenticatedGraphQLView, cls).as_view(*args, **kwargs)
view = permission_classes((IsAuthenticated,))(view)
view = authentication_classes(api_settings.DEFAULT_AUTHENTICATION_CLASSES)(view)
view = throttle_classes(api_settings.DEFAULT_THROTTLE_CLASSES)(view)
view = api_view(['GET', 'POST'])(view)

return view

0 comments on commit 12dc8c8

Please sign in to comment.