Package: graphene-django-filter
Graphene-Django-FilterThis package contains advanced filters forgraphene-django.
The standard filtering feature in graphene-django relies on thedjango-filterlibrary and therefore provides the flat API without the ability to use logical operators such asand,orandnot. This library makes the API nested and adds logical expressions by extension
of theDjangoFilterConnectionFieldfield and theFilterSetclass.
Also, the library provides some other convenient filtering features.Installation# pippipinstallgraphene-django-filter# poetrypoetryaddgraphene-django-filterRequirementsPython (3.7, 3.8, 3.9, 3.10)Graphene-Django (2.15)FeaturesNested API with the ability to use logical operatorsTo use, simply replace allDjangoFilterConnectionFieldfields withAdvancedDjangoFilterConnectionFieldfields in your queries.
Also,if you create custom FilterSets, replace the inheritance from theFilterSetclass
with the inheritance from theAdvancedFilterSetclass.
For example, the following task query exposes the old flat API.importgraphenefromdjango_filtersimportFilterSetfromgraphene_djangoimportDjangoObjectTypefromgraphene_django.filterimportDjangoFilterConnectionFieldclassTaskFilter(FilterSet):classMeta:model=Taskfields={'name':('exact','contains'),'user__email':('exact','contains'),'user__first_name':('exact','contains'),'user__last_name':('exact','contains'),}classUserType(DjangoObjectType):classMeta:model=Userinterfaces=(graphene.relay.Node,)fields='__all__'classTaskType(DjangoObjectType):user=graphene.Field(UserType)classMeta:model=Taskinterfaces=(graphene.relay.Node,)fields='__all__'filterset_class=TaskFilterclassQuery(graphene.ObjectType):tasks=DjangoFilterConnectionField(TaskType)The flat API in which all filters are applied using theandoperator looks like this.{tasks(name_Contains:"important"user_Email_Contains:"john"user_FirstName:"John"user_LastName:"Dou"){edges{node{idname}}}}After replacing the field class with theAdvancedDjangoFilterConnectionFieldand theFilterSetclass with theAdvancedFilterSetthe API becomes nested with support for logical expressions.importgraphenefromgraphene_django_filterimportAdvancedDjangoFilterConnectionField,AdvancedFilterSetclassTaskFilter(AdvancedFilterSet):classMeta:model=Taskfields={'name':('exact','contains'),'user__email':('exact','contains'),'user__first_name':('exact','contains'),'user__last_name':('exact','contains'),}classQuery(graphene.ObjectType):tasks=AdvancedDjangoFilterConnectionField(TaskType)For example, the following query returns tasks which names contain the word "important"
or the user's email address contains the word "john" and the user's last name is "Dou"
and the first name is not "John".
Note that the operators are applied to lookups
such ascontains,exact, etc. at the last level of nesting.{tasks(filter:{or:[{name:{contains:"important"}}{and:[{user:{email:{contains:"john"}}}{user:{lastName:{exact:"Dou"}}}]}]not:{user:{firstName:{exact:"John"}}}}){edges{node{idname}}}}The same result can be achieved with an alternative query structure
because within the same object theandoperator is always used.{tasks(filter:{or:[{name:{contains:"important"}}{user:{email:{contains:"john"}lastName:{exact:"Dou"}}}]not:{user:{firstName:{exact:"John"}}}}){edges{node{idname}}}}The filter input type has the following structure.inputFilterInputType{and:[FilterInputType]or:[FilterInputType]not:FilterInputType...FieldLookups}For more examples, seetests.Full text searchDjango provides theAPIfor PostgreSQL full text search. Graphene-Django-Filter inject this API into the GraphQL filter API.
To use, addfull_text_searchlookup to fields for which you want to enable full text search.
For example, the following type has full text search forfirst_nameandlast_namefields.importgraphenefromgraphene_djangoimportDjangoObjectTypefromgraphene_django_filterimportAdvancedDjangoFilterConnectionFieldclassUserType(DjangoObjectType):classMeta:model=Userinterfaces=(graphene.relay.Node,)fields='__all__'filter_fields={'email':('exact','startswith','contains'),'first_name':('exact','contains','full_text_search'),'last_name':('exact','contains','full_text_search'),}classQuery(graphene.ObjectType):users=AdvancedDjangoFilterConnectionField(UserType)Since this feature belongs to the AdvancedFilterSet,
it can be used in a custom FilterSet.
The following example will work exactly like the previous one.importgraphenefromgraphene_djangoimportDjangoObjectTypefromgraphene_django_filterimportAdvancedDjangoFilterConnectionField,AdvancedFilterSetclassUserFilter(AdvancedFilterSet):classMeta:model=Userfields={'email':('exact','startswith','contains'),'first_name':('exact','contains','full_text_search'),'last_name':('exact','contains','full_text_search'),}classUserType(DjangoObjectType):classMeta:model=Userinterfaces=(graphene.relay.Node,)fields='__all__'filterset_class=UserFilterclassQuery(graphene.ObjectType):users=AdvancedDjangoFilterConnectionField(UserType)Full text search API includes SearchQuery, SearchRank, and Trigram filters.
SearchQuery and SearchRank filters are at the top level.
If some field has been enabled for full text search then it can be included in the field array.
The following queries show an example of using the SearchQuery and SearchRank filters.{users(filter:{searchQuery:{vector:{fields:["first_name"]}query:{or:[{value:"Bob"}{value:"Alice"}]}}}){edges{node{idfirstNamelastName}}}}{users(filter:{searchRank:{vector:{fields:["first_name","last_name"]}query:{value:"John Dou"}lookups:{gte:0.5}}}){edges{node{idfirstNamelastName}}}}Trigram filter belongs to the corresponding field.
The following query shows an example of using the Trigram filter.{users(filter:{firstName:{trigram:{value:"john"lookups:{gte:0.85}}}}){edges{node{idfirstNamelastName}}}}Input types have the following structure.inputSearchConfigInputType{value:String!isField:Boolean}enumSearchVectorWeight{ABCD}inputSearchVectorInputType{fields:[String!]!config:SearchConfigInputTypeweight:SearchVectorWeight}enumSearchQueryType{PLAINPHRASERAWWEBSEARCH}inputSearchQueryInputType{value:Stringconfig:SearchConfigInputTypeand:[SearchQueryInputType]or:[SearchQueryInputType]not:SearchQueryInputType}inputSearchQueryFilterInputType{vector:SearchVectorInputType!query:SearchQueryInputType!}inputFloatLookupsInputType{exact:Floatgt:Floatgte:Floatlt:Floatlte:Float}inputSearchRankWeightsInputType{D:FloatC:FloatB:FloatA:Float}inputSearchRankFilterInputType{vector:SearchVectorInputType!query:SearchQueryInputType!lookups:FloatLookupsInputType!weights:SearchRankWeightsInputTypecoverDensity:Booleannormalization:Int}enumTrigramSearchKind{SIMILARITYDISTANCE}inputTrigramFilterInputType{kind:TrigramSearchKindlookups:FloatLookupsInputType!value:String!}For more examples, seetests.SettingsThe library can be customised using settings.
To add settings, create a dictionary
with nameGRAPHENE_DJANGO_FILTERin the project’ssettings.py.
The default settings are as follows.GRAPHENE_DJANGO_FILTER={'FILTER_KEY':'filter','AND_KEY':'and','OR_KEY':'or','NOT_KEY':'not',}To read the settings, import them from theconfmodule.fromgraphene_django_filter.confimportsettingsprint(settings.FILTER_KEY)Thesettingsobject also includes fixed settings, which depend on the user's environment.IS_POSTGRESQLdeterminate that current database is PostgreSQL
andHAS_TRIGRAM_EXTENSIONthatpg_trgmextension is installed.