mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-22 17:46:57 +03:00
Improved resolvers in Django
This commit is contained in:
parent
33c58f6cfa
commit
e1145b88fb
|
@ -1,28 +1,44 @@
|
||||||
import warnings
|
|
||||||
|
|
||||||
from ...core.exceptions import SkipField
|
from ...core.exceptions import SkipField
|
||||||
from ...core.fields import Field
|
from ...core.fields import Field
|
||||||
from ...core.types.base import FieldType
|
from ...core.types.base import FieldType
|
||||||
from ...core.types.definitions import List
|
from ...core.types.definitions import List
|
||||||
from ...relay import ConnectionField
|
from ...relay import ConnectionField
|
||||||
from ...relay.utils import is_node
|
from ...relay.utils import is_node
|
||||||
from .filter.fields import DjangoFilterConnectionField
|
from .utils import get_type_for_model, maybe_queryset
|
||||||
from .utils import get_type_for_model
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoConnectionField(ConnectionField):
|
class DjangoConnectionField(ConnectionField):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
cls = self.__class__
|
self.on = kwargs.pop('on', False)
|
||||||
warnings.warn("Using {} will be not longer supported."
|
|
||||||
" Use relay.ConnectionField instead".format(cls.__name__),
|
|
||||||
FutureWarning)
|
|
||||||
return super(DjangoConnectionField, self).__init__(*args, **kwargs)
|
return super(DjangoConnectionField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model(self):
|
||||||
|
return self.type._meta.model
|
||||||
|
|
||||||
|
def get_manager(self):
|
||||||
|
if self.on:
|
||||||
|
return getattr(self.model, self.on)
|
||||||
|
else:
|
||||||
|
return self.model._default_manager
|
||||||
|
|
||||||
|
def get_queryset(self, resolved_qs, args, info):
|
||||||
|
return resolved_qs
|
||||||
|
|
||||||
|
def from_list(self, connection_type, resolved, args, info):
|
||||||
|
if not resolved:
|
||||||
|
resolved = self.get_manager()
|
||||||
|
resolved_qs = maybe_queryset(resolved)
|
||||||
|
qs = self.get_queryset(resolved_qs, args, info)
|
||||||
|
return super(DjangoConnectionField, self).from_list(connection_type, qs, args, info)
|
||||||
|
|
||||||
|
|
||||||
class ConnectionOrListField(Field):
|
class ConnectionOrListField(Field):
|
||||||
|
|
||||||
def internal_type(self, schema):
|
def internal_type(self, schema):
|
||||||
|
from .filter.fields import DjangoFilterConnectionField
|
||||||
|
|
||||||
model_field = self.type
|
model_field = self.type
|
||||||
field_object_type = model_field.get_object_type(schema)
|
field_object_type = model_field.get_object_type(schema)
|
||||||
if not field_object_type:
|
if not field_object_type:
|
||||||
|
@ -31,7 +47,7 @@ class ConnectionOrListField(Field):
|
||||||
if field_object_type._meta.filter_fields:
|
if field_object_type._meta.filter_fields:
|
||||||
field = DjangoFilterConnectionField(field_object_type)
|
field = DjangoFilterConnectionField(field_object_type)
|
||||||
else:
|
else:
|
||||||
field = ConnectionField(field_object_type)
|
field = DjangoConnectionField(field_object_type)
|
||||||
else:
|
else:
|
||||||
field = Field(List(field_object_type))
|
field = Field(List(field_object_type))
|
||||||
field.contribute_to_class(self.object_type, self.attname)
|
field.contribute_to_class(self.object_type, self.attname)
|
||||||
|
|
|
@ -1,25 +1,36 @@
|
||||||
from graphene.contrib.django.filter.resolvers import FilterConnectionResolver
|
from .utils import get_filterset_class, get_filtering_args_from_filterset
|
||||||
from graphene.contrib.django.utils import get_filtering_args_from_filterset
|
from ..fields import DjangoConnectionField
|
||||||
from graphene.relay import ConnectionField
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoFilterConnectionField(ConnectionField):
|
class DjangoFilterConnectionField(DjangoConnectionField):
|
||||||
|
|
||||||
def __init__(self, type, on=None, fields=None, order_by=None,
|
def __init__(self, type, fields=None, order_by=None,
|
||||||
extra_filter_meta=None, filterset_class=None, resolver=None,
|
extra_filter_meta=None, filterset_class=None,
|
||||||
*args, **kwargs):
|
*args, **kwargs):
|
||||||
|
|
||||||
if not resolver:
|
self.order_by = order_by or type._meta.filter_order_by
|
||||||
resolver = FilterConnectionResolver(
|
self.fields = fields or type._meta.filter_fields
|
||||||
node=type,
|
meta = dict(model=type._meta.model,
|
||||||
on=on,
|
fields=self.fields,
|
||||||
filterset_class=filterset_class,
|
order_by=self.order_by)
|
||||||
fields=fields,
|
if extra_filter_meta:
|
||||||
order_by=order_by,
|
meta.update(extra_filter_meta)
|
||||||
extra_filter_meta=extra_filter_meta,
|
self.filterset_class = get_filterset_class(filterset_class, **meta)
|
||||||
)
|
self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, type)
|
||||||
|
|
||||||
filtering_args = get_filtering_args_from_filterset(resolver.get_filterset_class(), type)
|
|
||||||
kwargs.setdefault('args', {})
|
kwargs.setdefault('args', {})
|
||||||
kwargs['args'].update(**filtering_args)
|
kwargs['args'].update(**self.filtering_args)
|
||||||
super(DjangoFilterConnectionField, self).__init__(type, resolver, *args, **kwargs)
|
super(DjangoFilterConnectionField, self).__init__(type, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_queryset(self, qs, args, info):
|
||||||
|
filterset_class = self.filterset_class
|
||||||
|
filter_kwargs = self.get_filter_kwargs(args)
|
||||||
|
order = self.get_order(args)
|
||||||
|
if order:
|
||||||
|
qs = qs.order_by(order)
|
||||||
|
return filterset_class(data=filter_kwargs, queryset=qs)
|
||||||
|
|
||||||
|
def get_filter_kwargs(self, args):
|
||||||
|
return {k: v for k, v in args.items() if k in self.filtering_args}
|
||||||
|
|
||||||
|
def get_order(self, args):
|
||||||
|
return args.get('order_by', None)
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
|
|
||||||
from graphene.contrib.django.filter.filterset import (custom_filterset_factory,
|
|
||||||
setup_filterset)
|
|
||||||
from graphene.contrib.django.resolvers import BaseQuerySetConnectionResolver
|
|
||||||
|
|
||||||
|
|
||||||
class FilterConnectionResolver(BaseQuerySetConnectionResolver):
|
|
||||||
# Querying using django-filter
|
|
||||||
|
|
||||||
def __init__(self, node, on=None, filterset_class=None,
|
|
||||||
fields=None, order_by=None, extra_filter_meta=None):
|
|
||||||
self.filterset_class = filterset_class
|
|
||||||
self.fields = fields or node._meta.filter_fields
|
|
||||||
self.order_by = order_by or node._meta.filter_order_by
|
|
||||||
self.extra_filter_meta = extra_filter_meta or {}
|
|
||||||
self._filterset_class = None
|
|
||||||
super(FilterConnectionResolver, self).__init__(node, on)
|
|
||||||
|
|
||||||
def make_query(self):
|
|
||||||
filterset_class = self.get_filterset_class()
|
|
||||||
filterset = self.get_filterset(filterset_class)
|
|
||||||
return filterset.qs
|
|
||||||
|
|
||||||
def get_filterset_class(self):
|
|
||||||
"""Get the class to be used as the FilterSet"""
|
|
||||||
if self._filterset_class:
|
|
||||||
return self._filterset_class
|
|
||||||
|
|
||||||
if self.filterset_class:
|
|
||||||
# If were given a FilterSet class, then set it up and
|
|
||||||
# return it
|
|
||||||
self._filterset_class = setup_filterset(self.filterset_class)
|
|
||||||
elif self.model:
|
|
||||||
# If no filter class was specified then create one given the
|
|
||||||
# other information provided
|
|
||||||
meta = dict(
|
|
||||||
model=self.model,
|
|
||||||
fields=self.fields,
|
|
||||||
order_by=self.order_by,
|
|
||||||
)
|
|
||||||
meta.update(self.extra_filter_meta)
|
|
||||||
self._filterset_class = custom_filterset_factory(**meta)
|
|
||||||
else:
|
|
||||||
msg = "Neither 'filterset_class' or 'model' available in '%s'. " \
|
|
||||||
"Either pass in 'filterset_class' or 'model' when " \
|
|
||||||
"initialising, or extend this class and override " \
|
|
||||||
"get_filterset() or get_filterset_class()"
|
|
||||||
raise ImproperlyConfigured(msg % self.__class__.__name__)
|
|
||||||
|
|
||||||
return self._filterset_class
|
|
||||||
|
|
||||||
def get_filterset(self, filterset_class):
|
|
||||||
"""Get an instance of the FilterSet"""
|
|
||||||
kwargs = self.get_filterset_kwargs(filterset_class)
|
|
||||||
return filterset_class(**kwargs)
|
|
||||||
|
|
||||||
def get_filterset_kwargs(self, filterset_class):
|
|
||||||
"""Get the kwargs to use when initialising the FilterSet class"""
|
|
||||||
kwargs = {
|
|
||||||
'data': self.args or None,
|
|
||||||
'queryset': self.get_manager()
|
|
||||||
}
|
|
||||||
return kwargs
|
|
|
@ -9,7 +9,7 @@ from graphene.contrib.django.forms import (GlobalIDFormField,
|
||||||
GlobalIDMultipleChoiceField)
|
GlobalIDMultipleChoiceField)
|
||||||
from graphene.contrib.django.tests.models import Article, Pet, Reporter
|
from graphene.contrib.django.tests.models import Article, Pet, Reporter
|
||||||
from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
|
from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
|
||||||
from graphene.relay import NodeField
|
from graphene.relay import NodeField, ConnectionField
|
||||||
from graphene.utils import ProxySnakeDict
|
from graphene.utils import ProxySnakeDict
|
||||||
|
|
||||||
pytestmark = []
|
pytestmark = []
|
||||||
|
@ -217,7 +217,7 @@ def test_filter_filterset_related_results():
|
||||||
|
|
||||||
def test_global_id_field_implicit():
|
def test_global_id_field_implicit():
|
||||||
field = DjangoFilterConnectionField(ArticleNode, fields=['id'])
|
field = DjangoFilterConnectionField(ArticleNode, fields=['id'])
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
id_filter = filterset_class.base_filters['id']
|
id_filter = filterset_class.base_filters['id']
|
||||||
assert isinstance(id_filter, GlobalIDFilter)
|
assert isinstance(id_filter, GlobalIDFilter)
|
||||||
assert id_filter.field_class == GlobalIDFormField
|
assert id_filter.field_class == GlobalIDFormField
|
||||||
|
@ -231,7 +231,7 @@ def test_global_id_field_explicit():
|
||||||
fields = ['id']
|
fields = ['id']
|
||||||
|
|
||||||
field = DjangoFilterConnectionField(ArticleNode, filterset_class=ArticleIdFilter)
|
field = DjangoFilterConnectionField(ArticleNode, filterset_class=ArticleIdFilter)
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
id_filter = filterset_class.base_filters['id']
|
id_filter = filterset_class.base_filters['id']
|
||||||
assert isinstance(id_filter, GlobalIDFilter)
|
assert isinstance(id_filter, GlobalIDFilter)
|
||||||
assert id_filter.field_class == GlobalIDFormField
|
assert id_filter.field_class == GlobalIDFormField
|
||||||
|
@ -239,7 +239,7 @@ def test_global_id_field_explicit():
|
||||||
|
|
||||||
def test_global_id_field_relation():
|
def test_global_id_field_relation():
|
||||||
field = DjangoFilterConnectionField(ArticleNode, fields=['reporter'])
|
field = DjangoFilterConnectionField(ArticleNode, fields=['reporter'])
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
id_filter = filterset_class.base_filters['reporter']
|
id_filter = filterset_class.base_filters['reporter']
|
||||||
assert isinstance(id_filter, GlobalIDFilter)
|
assert isinstance(id_filter, GlobalIDFilter)
|
||||||
assert id_filter.field_class == GlobalIDFormField
|
assert id_filter.field_class == GlobalIDFormField
|
||||||
|
@ -247,7 +247,7 @@ def test_global_id_field_relation():
|
||||||
|
|
||||||
def test_global_id_multiple_field_implicit():
|
def test_global_id_multiple_field_implicit():
|
||||||
field = DjangoFilterConnectionField(ReporterNode, fields=['pets'])
|
field = DjangoFilterConnectionField(ReporterNode, fields=['pets'])
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
multiple_filter = filterset_class.base_filters['pets']
|
multiple_filter = filterset_class.base_filters['pets']
|
||||||
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
||||||
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
||||||
|
@ -261,7 +261,7 @@ def test_global_id_multiple_field_explicit():
|
||||||
fields = ['pets']
|
fields = ['pets']
|
||||||
|
|
||||||
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
|
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
multiple_filter = filterset_class.base_filters['pets']
|
multiple_filter = filterset_class.base_filters['pets']
|
||||||
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
||||||
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
||||||
|
@ -269,7 +269,7 @@ def test_global_id_multiple_field_explicit():
|
||||||
|
|
||||||
def test_global_id_multiple_field_implicit_reverse():
|
def test_global_id_multiple_field_implicit_reverse():
|
||||||
field = DjangoFilterConnectionField(ReporterNode, fields=['articles'])
|
field = DjangoFilterConnectionField(ReporterNode, fields=['articles'])
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
multiple_filter = filterset_class.base_filters['articles']
|
multiple_filter = filterset_class.base_filters['articles']
|
||||||
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
||||||
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
||||||
|
@ -283,7 +283,7 @@ def test_global_id_multiple_field_explicit_reverse():
|
||||||
fields = ['articles']
|
fields = ['articles']
|
||||||
|
|
||||||
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
|
field = DjangoFilterConnectionField(ReporterNode, filterset_class=ReporterPetsFilter)
|
||||||
filterset_class = field.resolver_fn.get_filterset_class()
|
filterset_class = field.filterset_class
|
||||||
multiple_filter = filterset_class.base_filters['articles']
|
multiple_filter = filterset_class.base_filters['articles']
|
||||||
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
assert isinstance(multiple_filter, GlobalIDMultipleChoiceFilter)
|
||||||
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
assert multiple_filter.field_class == GlobalIDMultipleChoiceField
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
import pytest
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
|
|
||||||
from graphene.contrib.django.tests.models import Article, Reporter
|
|
||||||
from graphene.contrib.django.tests.test_resolvers import (ArticleNode,
|
|
||||||
ReporterNode)
|
|
||||||
from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
|
|
||||||
|
|
||||||
if DJANGO_FILTER_INSTALLED:
|
|
||||||
from graphene.contrib.django.filter.resolvers import FilterConnectionResolver
|
|
||||||
from graphene.contrib.django.filter.tests.filters import ArticleFilter, ReporterFilter
|
|
||||||
else:
|
|
||||||
pytestmark = pytest.mark.skipif(True, reason='django_filters not installed')
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_get_filterset_class_explicit():
|
|
||||||
reporter = Reporter(id=1, first_name='Cookie Monster')
|
|
||||||
resolver = FilterConnectionResolver(ReporterNode,
|
|
||||||
filterset_class=ReporterFilter)
|
|
||||||
resolver(inst=reporter, args={}, info=None)
|
|
||||||
assert issubclass(resolver.get_filterset_class(), ReporterFilter), \
|
|
||||||
'ReporterFilter not returned'
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_get_filterset_class_implicit():
|
|
||||||
reporter = Reporter(id=1, first_name='Cookie Monster')
|
|
||||||
resolver = FilterConnectionResolver(ReporterNode)
|
|
||||||
resolver(inst=reporter, args={}, info=None)
|
|
||||||
assert resolver.get_filterset_class().__name__ == 'ReporterFilterSet'
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_get_filterset_class_error():
|
|
||||||
reporter = Reporter(id=1, first_name='Cookie Monster')
|
|
||||||
resolver = FilterConnectionResolver(ReporterNode)
|
|
||||||
resolver.model = None
|
|
||||||
with pytest.raises(ImproperlyConfigured) as excinfo:
|
|
||||||
resolver(inst=reporter, args={}, info=None)
|
|
||||||
assert "Neither 'filterset_class' or 'model' available" in str(excinfo.value)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_filter():
|
|
||||||
reporter = Reporter(id=1, first_name='Cookie Monster')
|
|
||||||
resolver = FilterConnectionResolver(ReporterNode,
|
|
||||||
filterset_class=ReporterFilter)
|
|
||||||
resolved = resolver(inst=reporter, args={
|
|
||||||
'first_name': 'Elmo'
|
|
||||||
}, info=None)
|
|
||||||
assert '"first_name" = Elmo' in str(resolved.query)
|
|
||||||
assert 'ORDER BY' not in str(resolved.query)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_filter_contains():
|
|
||||||
article = Article(id=1, headline='Cookie Monster eats fruit')
|
|
||||||
resolver = FilterConnectionResolver(ArticleNode,
|
|
||||||
filterset_class=ArticleFilter)
|
|
||||||
resolved = resolver(inst=article, args={
|
|
||||||
'headline__icontains': 'Elmo'
|
|
||||||
}, info=None)
|
|
||||||
assert '"headline" LIKE %Elmo%' in str(resolved.query)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_order():
|
|
||||||
article = Article(id=1, headline='Cookie Monster eats fruit')
|
|
||||||
resolver = FilterConnectionResolver(ArticleNode,
|
|
||||||
filterset_class=ArticleFilter)
|
|
||||||
resolved = resolver(inst=article, args={
|
|
||||||
'order_by': 'headline'
|
|
||||||
}, info=None)
|
|
||||||
assert 'WHERE' not in str(resolved.query)
|
|
||||||
assert 'ORDER BY' in str(resolved.query)
|
|
||||||
assert '"headline" ASC' in str(resolved.query)
|
|
||||||
|
|
||||||
|
|
||||||
def test_filter_order_not_available():
|
|
||||||
reporter = Reporter(id=1, first_name='Cookie Monster')
|
|
||||||
resolver = FilterConnectionResolver(ReporterNode,
|
|
||||||
filterset_class=ReporterFilter)
|
|
||||||
resolved = resolver(inst=reporter, args={
|
|
||||||
'order_by': 'last_name'
|
|
||||||
}, info=None)
|
|
||||||
assert 'WHERE' not in str(resolved.query)
|
|
||||||
assert 'ORDER BY' not in str(resolved.query)
|
|
31
graphene/contrib/django/filter/utils.py
Normal file
31
graphene/contrib/django/filter/utils.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import six
|
||||||
|
|
||||||
|
from .filterset import custom_filterset_factory, setup_filterset
|
||||||
|
from ....core.types import Argument, String
|
||||||
|
|
||||||
|
|
||||||
|
def get_filtering_args_from_filterset(filterset_class, type):
|
||||||
|
""" Inspect a FilterSet and produce the arguments to pass to
|
||||||
|
a Graphene Field. These arguments will be available to
|
||||||
|
filter against in the GraphQL
|
||||||
|
"""
|
||||||
|
from graphene.contrib.django.form_converter import convert_form_field
|
||||||
|
|
||||||
|
args = {}
|
||||||
|
for name, filter_field in six.iteritems(filterset_class.base_filters):
|
||||||
|
field_type = Argument(convert_form_field(filter_field.field))
|
||||||
|
args[name] = field_type
|
||||||
|
|
||||||
|
# Also add the 'order_by' field
|
||||||
|
if filterset_class._meta.order_by:
|
||||||
|
args[filterset_class.order_by_field] = Argument(String())
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def get_filterset_class(filterset_class, **meta):
|
||||||
|
"""Get the class to be used as the FilterSet"""
|
||||||
|
if filterset_class:
|
||||||
|
# If were given a FilterSet class, then set it up and
|
||||||
|
# return it
|
||||||
|
return setup_filterset(filterset_class)
|
||||||
|
return custom_filterset_factory(**meta)
|
|
@ -1,43 +0,0 @@
|
||||||
class BaseQuerySetConnectionResolver(object):
|
|
||||||
|
|
||||||
def __init__(self, node, on=None):
|
|
||||||
self.node = node
|
|
||||||
self.model = node._meta.model
|
|
||||||
# The name of the field on the model which contains the
|
|
||||||
# manager upon which to perform the query. Optional.
|
|
||||||
# If omitted the model's default manager will be used.
|
|
||||||
self.on = on
|
|
||||||
|
|
||||||
def __call__(self, inst, args, info):
|
|
||||||
self.inst = inst
|
|
||||||
self.args = args
|
|
||||||
self.info = info
|
|
||||||
return self.make_query()
|
|
||||||
|
|
||||||
def get_manager(self):
|
|
||||||
if self.on:
|
|
||||||
return getattr(self.inst, self.on)
|
|
||||||
else:
|
|
||||||
return self.model._default_manager
|
|
||||||
|
|
||||||
def make_query(self):
|
|
||||||
raise NotImplemented()
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleQuerySetConnectionResolver(BaseQuerySetConnectionResolver):
|
|
||||||
# Simple querying without using django-filter (ported from previous gist)
|
|
||||||
|
|
||||||
def make_query(self):
|
|
||||||
filter_kwargs = self.get_filter_kwargs()
|
|
||||||
query = self.get_manager().filter(**filter_kwargs)
|
|
||||||
order = self.get_order()
|
|
||||||
if order:
|
|
||||||
query = query.order_by(order)
|
|
||||||
return query
|
|
||||||
|
|
||||||
def get_filter_kwargs(self):
|
|
||||||
ignore = ['first', 'last', 'before', 'after', 'order_by']
|
|
||||||
return {k: v for k, v in self.args.items() if k not in ignore}
|
|
||||||
|
|
||||||
def get_order(self):
|
|
||||||
return self.args.get('order_by', None)
|
|
|
@ -7,7 +7,7 @@ from ...core.classtypes.objecttype import ObjectType, ObjectTypeMeta
|
||||||
from ...relay.types import Connection, Node, NodeMeta
|
from ...relay.types import Connection, Node, NodeMeta
|
||||||
from .converter import convert_django_field
|
from .converter import convert_django_field
|
||||||
from .options import DjangoOptions
|
from .options import DjangoOptions
|
||||||
from .utils import get_reverse_fields, maybe_queryset
|
from .utils import get_reverse_fields
|
||||||
|
|
||||||
|
|
||||||
class DjangoObjectTypeMeta(ObjectTypeMeta):
|
class DjangoObjectTypeMeta(ObjectTypeMeta):
|
||||||
|
@ -82,11 +82,7 @@ class DjangoObjectType(six.with_metaclass(
|
||||||
|
|
||||||
|
|
||||||
class DjangoConnection(Connection):
|
class DjangoConnection(Connection):
|
||||||
|
pass
|
||||||
@classmethod
|
|
||||||
def from_list(cls, iterable, *args, **kwargs):
|
|
||||||
iterable = maybe_queryset(iterable)
|
|
||||||
return super(DjangoConnection, cls).from_list(iterable, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta):
|
class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta):
|
||||||
|
@ -112,5 +108,3 @@ class DjangoNode(six.with_metaclass(
|
||||||
return cls(instance)
|
return cls(instance)
|
||||||
except cls._meta.model.DoesNotExist:
|
except cls._meta.model.DoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
connection_type = DjangoConnection
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import six
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.manager import Manager
|
from django.db.models.manager import Manager
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
from graphene import Argument, String
|
|
||||||
from graphene.utils import LazyList
|
from graphene.utils import LazyList
|
||||||
|
|
||||||
from .compat import RelatedObject
|
from .compat import RelatedObject
|
||||||
|
@ -56,26 +54,6 @@ def maybe_queryset(value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def get_filtering_args_from_filterset(filterset_class, type):
|
|
||||||
""" Inspect a FilterSet and produce the arguments to pass to
|
|
||||||
a Graphene Field. These arguments will be available to
|
|
||||||
filter against in the GraphQL
|
|
||||||
"""
|
|
||||||
from graphene.contrib.django.form_converter import convert_form_field
|
|
||||||
|
|
||||||
args = {}
|
|
||||||
for name, filter_field in six.iteritems(filterset_class.base_filters):
|
|
||||||
field_type = Argument(convert_form_field(filter_field.field))
|
|
||||||
# Is this correct? I don't quite grok the 'parent' system yet
|
|
||||||
field_type.mount(type)
|
|
||||||
args[name] = field_type
|
|
||||||
|
|
||||||
# Also add the 'order_by' field
|
|
||||||
if filterset_class._meta.order_by:
|
|
||||||
args[filterset_class.order_by_field] = Argument(String())
|
|
||||||
return args
|
|
||||||
|
|
||||||
|
|
||||||
def get_related_model(field):
|
def get_related_model(field):
|
||||||
if hasattr(field, 'rel'):
|
if hasattr(field, 'rel'):
|
||||||
# Django 1.6, 1.7
|
# Django 1.6, 1.7
|
||||||
|
|
Loading…
Reference in New Issue
Block a user