mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 09:57:53 +03:00 
			
		
		
		
	Making GrapheneFilterSetMixin compatible with django_filter 2
This commit is contained in:
		
							parent
							
								
									14f156ef5f
								
							
						
					
					
						commit
						dc0c2900d1
					
				| 
						 | 
				
			
			@ -2,11 +2,9 @@ Filtering
 | 
			
		|||
=========
 | 
			
		||||
 | 
			
		||||
Graphene integrates with
 | 
			
		||||
`django-filter <https://django-filter.readthedocs.io/en/1.1.0/>`__ (< 2.0.0) to provide
 | 
			
		||||
filtering of results (this also means filtering is only compatible with Django < 2.0).
 | 
			
		||||
 | 
			
		||||
See the `usage
 | 
			
		||||
documentation <https://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#the-filter>`__
 | 
			
		||||
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ (2.x for
 | 
			
		||||
Python 3 or 1.x for Python 2) to provide filtering of results. See the `usage
 | 
			
		||||
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
 | 
			
		||||
for details on the format for ``filter_fields``.
 | 
			
		||||
 | 
			
		||||
This filtering is automatically available when implementing a ``relay.Node``.
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +15,7 @@ You will need to install it manually, which can be done as follows:
 | 
			
		|||
.. code:: bash
 | 
			
		||||
 | 
			
		||||
    # You'll need to django-filter
 | 
			
		||||
    pip install django-filter==1.1.0
 | 
			
		||||
    pip install django-filter>=2
 | 
			
		||||
 | 
			
		||||
Note: The techniques below are demoed in the `cookbook example
 | 
			
		||||
app <https://github.com/graphql-python/graphene-django/tree/master/examples/cookbook>`__.
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +26,7 @@ Filterable fields
 | 
			
		|||
The ``filter_fields`` parameter is used to specify the fields which can
 | 
			
		||||
be filtered upon. The value specified here is passed directly to
 | 
			
		||||
``django-filter``, so see the `filtering
 | 
			
		||||
documentation <https://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#the-filter>`__
 | 
			
		||||
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
 | 
			
		||||
for full details on the range of options available.
 | 
			
		||||
 | 
			
		||||
For example:
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +127,7 @@ create your own ``Filterset`` as follows:
 | 
			
		|||
        all_animals = DjangoFilterConnectionField(AnimalNode,
 | 
			
		||||
                                                  filterset_class=AnimalFilter)
 | 
			
		||||
 | 
			
		||||
The context argument is passed on as the `request argument <http://django-filter.readthedocs.io/en/1.1.0/guide/usage.html#request-based-filtering>`__
 | 
			
		||||
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
 | 
			
		||||
pre-filter animals owned by the authenticated user (set in ``context.user``).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,4 +2,4 @@ graphene
 | 
			
		|||
graphene-django
 | 
			
		||||
graphql-core>=2.1rc1
 | 
			
		||||
django==1.9
 | 
			
		||||
django-filter<2
 | 
			
		||||
django-filter>=2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import itertools
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.text import capfirst
 | 
			
		||||
from django_filters import Filter, MultipleChoiceFilter
 | 
			
		||||
from django_filters.filterset import BaseFilterSet, FilterSet
 | 
			
		||||
from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +14,10 @@ class GlobalIDFilter(Filter):
 | 
			
		|||
    field_class = GlobalIDFormField
 | 
			
		||||
 | 
			
		||||
    def filter(self, qs, value):
 | 
			
		||||
        _type, _id = from_global_id(value)
 | 
			
		||||
        """ Convert the filter value to a primary key before filtering """
 | 
			
		||||
        _id = None
 | 
			
		||||
        if value is not None:
 | 
			
		||||
            _, _id = from_global_id(value)
 | 
			
		||||
        return super(GlobalIDFilter, self).filter(qs, _id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,37 +34,22 @@ GRAPHENE_FILTER_SET_OVERRIDES = {
 | 
			
		|||
    models.OneToOneField: {"filter_class": GlobalIDFilter},
 | 
			
		||||
    models.ForeignKey: {"filter_class": GlobalIDFilter},
 | 
			
		||||
    models.ManyToManyField: {"filter_class": GlobalIDMultipleChoiceFilter},
 | 
			
		||||
    models.ManyToOneRel: {"filter_class": GlobalIDMultipleChoiceFilter},
 | 
			
		||||
    models.ManyToManyRel: {"filter_class": GlobalIDMultipleChoiceFilter},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GrapheneFilterSetMixin(BaseFilterSet):
 | 
			
		||||
    """ A django_filters.filterset.BaseFilterSet with default filter overrides
 | 
			
		||||
    to handle global IDs """
 | 
			
		||||
 | 
			
		||||
    FILTER_DEFAULTS = dict(
 | 
			
		||||
        itertools.chain(
 | 
			
		||||
            FILTER_FOR_DBFIELD_DEFAULTS.items(), GRAPHENE_FILTER_SET_OVERRIDES.items()
 | 
			
		||||
            FILTER_FOR_DBFIELD_DEFAULTS.items(),
 | 
			
		||||
            GRAPHENE_FILTER_SET_OVERRIDES.items()
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def filter_for_reverse_field(cls, f, name):
 | 
			
		||||
        """Handles retrieving filters for reverse relationships
 | 
			
		||||
 | 
			
		||||
        We override the default implementation so that we can handle
 | 
			
		||||
        Global IDs (the default implementation expects database
 | 
			
		||||
        primary keys)
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            rel = f.field.remote_field
 | 
			
		||||
        except AttributeError:
 | 
			
		||||
            rel = f.field.rel
 | 
			
		||||
 | 
			
		||||
        default = {"name": name, "label": capfirst(rel.related_name)}
 | 
			
		||||
        if rel.multiple:
 | 
			
		||||
            # For to-many relationships
 | 
			
		||||
            return GlobalIDMultipleChoiceFilter(**default)
 | 
			
		||||
        else:
 | 
			
		||||
            # For to-one relationships
 | 
			
		||||
            return GlobalIDFilter(**default)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup_filterset(filterset_class):
 | 
			
		||||
    """ Wrap a provided filterset in Graphene-specific functionality
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								setup.py
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -19,7 +19,7 @@ tests_require = [
 | 
			
		|||
    "coveralls",
 | 
			
		||||
    "mock",
 | 
			
		||||
    "pytz",
 | 
			
		||||
    "django-filter<2",
 | 
			
		||||
    "django-filter>=2",
 | 
			
		||||
    "pytest-django>=3.3.2",
 | 
			
		||||
] + rest_framework_require
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ setup(
 | 
			
		|||
        "six>=1.10.0",
 | 
			
		||||
        "graphene>=2.1,<3",
 | 
			
		||||
        "graphql-core>=2.1rc1",
 | 
			
		||||
        "Django>=1.8.0",
 | 
			
		||||
        "Django>=1.11",
 | 
			
		||||
        "iso8601",
 | 
			
		||||
        "singledispatch>=3.4.0.3",
 | 
			
		||||
        "promise>=2.1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user