mirror of
https://github.com/graphql-python/graphene-django.git
synced 2024-11-22 09:37:07 +03:00
Add support for filterset_class meta parameter
* Allow for use of either filter_fields or filterset_class * Add tests to check that the behavior is similar to filter_fields * Add documentation to show how to make use of the parameter
This commit is contained in:
parent
ea2cd9894f
commit
5c191b9062
|
@ -100,7 +100,7 @@ features of ``django-filter``. This is done by transparently creating a
|
|||
``filter_fields``.
|
||||
|
||||
However, you may find this to be insufficient. In these cases you can
|
||||
create your own ``Filterset`` as follows:
|
||||
create your own ``FilterSet``. You can pass it directly as follows:
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
@ -127,6 +127,33 @@ create your own ``Filterset`` as follows:
|
|||
all_animals = DjangoFilterConnectionField(AnimalNode,
|
||||
filterset_class=AnimalFilter)
|
||||
|
||||
You can also specify the ``FilterSet`` class using the ``filerset_class``
|
||||
parameter when defining your ``DjangoObjectType``, however, this can't be used
|
||||
in unison with the ``filter_fields`` parameter:
|
||||
|
||||
.. code:: python
|
||||
|
||||
class AnimalFilter(django_filters.FilterSet):
|
||||
# Do case-insensitive lookups on 'name'
|
||||
name = django_filters.CharFilter(lookup_expr=['iexact'])
|
||||
|
||||
class Meta:
|
||||
# Assume you have an Animal model defined with the following fields
|
||||
model = Animal
|
||||
fields = ['name', 'genus', 'is_domesticated']
|
||||
|
||||
|
||||
class AnimalNode(DjangoObjectType):
|
||||
class Meta:
|
||||
model = Animal
|
||||
filterset_class = AnimalFilter
|
||||
interfaces = (relay.Node, )
|
||||
|
||||
|
||||
class Query(ObjectType):
|
||||
animal = relay.Node.Field(AnimalNode)
|
||||
all_animals = DjangoFilterConnectionField(AnimalNode)
|
||||
|
||||
The context argument is passed on as the `request argument <http://django-filter.readthedocs.io/en/master/guide/usage.html#request-based-filtering>`__
|
||||
in a ``django_filters.FilterSet`` instance. You can use this to customize your
|
||||
filters to be context-dependent. We could modify the ``AnimalFilter`` above to
|
||||
|
|
|
@ -181,8 +181,9 @@ def convert_field_to_list_or_connection(field, registry=None):
|
|||
# into a DjangoConnectionField
|
||||
if _type._meta.connection:
|
||||
# Use a DjangoFilterConnectionField if there are
|
||||
# defined filter_fields in the DjangoObjectType Meta
|
||||
if _type._meta.filter_fields:
|
||||
# defined filter_fields or a filterset_class in the
|
||||
# DjangoObjectType Meta
|
||||
if _type._meta.filter_fields or _type._meta.filterset_class:
|
||||
from .filter.fields import DjangoFilterConnectionField
|
||||
|
||||
return DjangoFilterConnectionField(_type)
|
||||
|
|
|
@ -35,14 +35,17 @@ class DjangoFilterConnectionField(DjangoConnectionField):
|
|||
@property
|
||||
def filterset_class(self):
|
||||
if not self._filterset_class:
|
||||
fields = self._fields or self.node_type._meta.filter_fields
|
||||
meta = dict(model=self.model, fields=fields)
|
||||
if self._extra_filter_meta:
|
||||
meta.update(self._extra_filter_meta)
|
||||
if not self.node_type._meta.filterset_class:
|
||||
fields = self._fields or self.node_type._meta.filter_fields
|
||||
meta = dict(model=self.model, fields=fields)
|
||||
if self._extra_filter_meta:
|
||||
meta.update(self._extra_filter_meta)
|
||||
|
||||
self._filterset_class = get_filterset_class(
|
||||
self._provided_filterset_class, **meta
|
||||
)
|
||||
self._filterset_class = get_filterset_class(
|
||||
self._provided_filterset_class, **meta
|
||||
)
|
||||
else:
|
||||
self._filterset_class = self.node_type._meta.filterset_class
|
||||
|
||||
return self._filterset_class
|
||||
|
||||
|
|
|
@ -227,6 +227,58 @@ def test_filter_filterset_information_on_meta_related():
|
|||
assert_not_orderable(articles_field)
|
||||
|
||||
|
||||
def test_filter_filterset_class_information_on_meta():
|
||||
class ReporterFilter(FilterSet):
|
||||
class Meta:
|
||||
model = Reporter
|
||||
fields = ["first_name", "articles"]
|
||||
|
||||
class ReporterFilterNode(DjangoObjectType):
|
||||
class Meta:
|
||||
model = Reporter
|
||||
interfaces = (Node,)
|
||||
filterset_class = ReporterFilter
|
||||
|
||||
field = DjangoFilterConnectionField(ReporterFilterNode)
|
||||
assert_arguments(field, "first_name", "articles")
|
||||
assert_not_orderable(field)
|
||||
|
||||
|
||||
def test_filter_filterset_class_information_on_meta_related():
|
||||
class ReporterFilter(FilterSet):
|
||||
class Meta:
|
||||
model = Reporter
|
||||
fields = ["first_name", "articles"]
|
||||
|
||||
class ArticleFilter(FilterSet):
|
||||
class Meta:
|
||||
model = Article
|
||||
fields = ["headline", "reporter"]
|
||||
|
||||
class ReporterFilterNode(DjangoObjectType):
|
||||
class Meta:
|
||||
model = Reporter
|
||||
interfaces = (Node,)
|
||||
filterset_class = ReporterFilter
|
||||
|
||||
class ArticleFilterNode(DjangoObjectType):
|
||||
class Meta:
|
||||
model = Article
|
||||
interfaces = (Node,)
|
||||
filterset_class = ArticleFilter
|
||||
|
||||
class Query(ObjectType):
|
||||
all_reporters = DjangoFilterConnectionField(ReporterFilterNode)
|
||||
all_articles = DjangoFilterConnectionField(ArticleFilterNode)
|
||||
reporter = Field(ReporterFilterNode)
|
||||
article = Field(ArticleFilterNode)
|
||||
|
||||
schema = Schema(query=Query)
|
||||
articles_field = ReporterFilterNode._meta.fields["articles"].get_type()
|
||||
assert_arguments(articles_field, "headline", "reporter")
|
||||
assert_not_orderable(articles_field)
|
||||
|
||||
|
||||
def test_filter_filterset_related_results():
|
||||
class ReporterFilterNode(DjangoObjectType):
|
||||
class Meta:
|
||||
|
|
|
@ -44,6 +44,7 @@ class DjangoObjectTypeOptions(ObjectTypeOptions):
|
|||
connection = None # type: Type[Connection]
|
||||
|
||||
filter_fields = ()
|
||||
filterset_class = None
|
||||
|
||||
|
||||
class DjangoObjectType(ObjectType):
|
||||
|
@ -56,6 +57,7 @@ class DjangoObjectType(ObjectType):
|
|||
only_fields=(),
|
||||
exclude_fields=(),
|
||||
filter_fields=None,
|
||||
filterset_class=None,
|
||||
connection=None,
|
||||
connection_class=None,
|
||||
use_connection=None,
|
||||
|
@ -74,9 +76,15 @@ class DjangoObjectType(ObjectType):
|
|||
"The attribute registry in {} needs to be an instance of "
|
||||
'Registry, received "{}".'
|
||||
).format(cls.__name__, registry)
|
||||
|
||||
if not DJANGO_FILTER_INSTALLED and filter_fields:
|
||||
raise Exception("Can only set filter_fields if Django-Filter is installed")
|
||||
|
||||
if filter_fields and filterset_class:
|
||||
raise Exception("Can't set both filter_fields and filterset_class")
|
||||
|
||||
if not DJANGO_FILTER_INSTALLED and (filter_fields or filterset_class):
|
||||
raise Exception((
|
||||
"Can only set filter_fields or filterset_class if "
|
||||
"Django-Filter is installed"
|
||||
))
|
||||
|
||||
django_fields = yank_fields_from_attrs(
|
||||
construct_fields(model, registry, only_fields, exclude_fields), _as=Field
|
||||
|
@ -107,6 +115,7 @@ class DjangoObjectType(ObjectType):
|
|||
_meta.model = model
|
||||
_meta.registry = registry
|
||||
_meta.filter_fields = filter_fields
|
||||
_meta.filterset_class = filterset_class
|
||||
_meta.fields = django_fields
|
||||
_meta.connection = connection
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user