11import itertools
22
33from django .db import models
4- from django .utils .text import capfirst
5- from django_filters import Filter , MultipleChoiceFilter
4+ from django_filters import Filter , MultipleChoiceFilter , VERSION
65from django_filters .filterset import BaseFilterSet , FilterSet
76from django_filters .filterset import FILTER_FOR_DBFIELD_DEFAULTS
87
@@ -15,7 +14,10 @@ class GlobalIDFilter(Filter):
1514 field_class = GlobalIDFormField
1615
1716 def filter (self , qs , value ):
18- _type , _id = from_global_id (value )
17+ """ Convert the filter value to a primary key before filtering """
18+ _id = None
19+ if value is not None :
20+ _ , _id = from_global_id (value )
1921 return super (GlobalIDFilter , self ).filter (qs , _id )
2022
2123
@@ -32,36 +34,52 @@ def filter(self, qs, value):
3234 models .OneToOneField : {"filter_class" : GlobalIDFilter },
3335 models .ForeignKey : {"filter_class" : GlobalIDFilter },
3436 models .ManyToManyField : {"filter_class" : GlobalIDMultipleChoiceFilter },
37+ models .ManyToOneRel : {"filter_class" : GlobalIDMultipleChoiceFilter },
38+ models .ManyToManyRel : {"filter_class" : GlobalIDMultipleChoiceFilter },
3539}
3640
3741
3842class GrapheneFilterSetMixin (BaseFilterSet ):
43+ """ A django_filters.filterset.BaseFilterSet with default filter overrides
44+ to handle global IDs """
45+
3946 FILTER_DEFAULTS = dict (
4047 itertools .chain (
41- FILTER_FOR_DBFIELD_DEFAULTS .items (), GRAPHENE_FILTER_SET_OVERRIDES .items ()
48+ FILTER_FOR_DBFIELD_DEFAULTS .items (),
49+ GRAPHENE_FILTER_SET_OVERRIDES .items ()
4250 )
4351 )
4452
45- @classmethod
46- def filter_for_reverse_field (cls , f , name ):
47- """Handles retrieving filters for reverse relationships
48-
49- We override the default implementation so that we can handle
50- Global IDs (the default implementation expects database
51- primary keys)
52- """
53- try :
54- rel = f .field .remote_field
55- except AttributeError :
56- rel = f .field .rel
57-
58- default = {"name" : name , "label" : capfirst (rel .related_name )}
59- if rel .multiple :
60- # For to-many relationships
61- return GlobalIDMultipleChoiceFilter (** default )
62- else :
63- # For to-one relationships
64- return GlobalIDFilter (** default )
53+
54+ # To support a Django 1.11 + Python 2.7 combination django-filter must be
55+ # < 2.x.x. To support the earlier version of django-filter, the
56+ # filter_for_reverse_field method must be present on GrapheneFilterSetMixin and
57+ # must not be present for later versions of django-filter.
58+ if VERSION [0 ] < 2 :
59+ from django .utils .text import capfirst
60+
61+ class GrapheneFilterSetMixinPython2 (GrapheneFilterSetMixin ):
62+
63+ @classmethod
64+ def filter_for_reverse_field (cls , f , name ):
65+ """Handles retrieving filters for reverse relationships
66+ We override the default implementation so that we can handle
67+ Global IDs (the default implementation expects database
68+ primary keys)
69+ """
70+ try :
71+ rel = f .field .remote_field
72+ except AttributeError :
73+ rel = f .field .rel
74+ default = {"name" : name , "label" : capfirst (rel .related_name )}
75+ if rel .multiple :
76+ # For to-many relationships
77+ return GlobalIDMultipleChoiceFilter (** default )
78+ else :
79+ # For to-one relationships
80+ return GlobalIDFilter (** default )
81+
82+ GrapheneFilterSetMixin = GrapheneFilterSetMixinPython2
6583
6684
6785def setup_filterset (filterset_class ):
0 commit comments