Skip to content

Full text search API improvement #29

@SquakR

Description

@SquakR

Problem

The current implementation of the full text search introduces new filter classes that extends the Filter class of the django_filters library. Using such filters in a FilterSet class is inconvenient and confusing because they must have specific field names and lookup expressions.
For example, the manual implementation of the trigram filter for a name field looks like the one below because of FloatLookupsInputType is the constant.

input FloatLookupsInputType {
  exact: Float
  gt: Float
  gte: Float
  lt: Float
  lte: Float
}
from graphene_django_filter import AdvancedFilterSet
from graphene_django_filter.filters import TrigramFilter

class ManualFilterSet(AdvancedFilterSet):
    name__trigram = TrigramFilter(field_name='name__trigram', lookup_expr='exact')
    name__trigram__gt = TrigramFilter(field_name='name__trigram', lookup_expr='gt')
    name__trigram__gte = TrigramFilter(field_name='name__trigram', lookup_expr='gte')
    name__trigram__lt = TrigramFilter(field_name='name__trigram', lookup_expr='lt')
    name__trigram__lte = TrigramFilter(field_name='name__trigram', lookup_expr='lte')

This is so confusing and verbose that it is not documented because it is always expected to use filters generation with the fields Meta field. For example.

from graphene_django_filter import AdvancedFilterSet

class AutoFilterSet(AdvancedFilterSet):
    class Meta:
        fields = {
            'name': ('full_text_search',)
        }

In general, the approach described above works, but it contradicts the logic of building the django_filters library. The 'full_text_search' is not a lookup expression but is used as such expression in the fields dictionary. The name__trigram is not a field name but is used as field name in the TrigramFilter class. The reasons for this approach were to try to reuse code as much as possible and avoid having to implement an additional Advanced DjangoObjectType that extends the DjangoObjectType class.

Suggested solution

The new API should look like this.

from graphene_django_filter import AdvancedFilterSet

class AutoFilterSet(AdvancedFilterSet):
    class Meta:
       full_text_search = {
           'trigram': {
                'name': ('exact', 'lt', 'gt',)
            },
            search_query: ('name', 'email')
            search_rank: {
                'fields': ('name', 'email')
                'lookups': ('exact', 'lt', 'gt',)
            }
       }

The logic of applying filtering and annotations will be moved to the level of the AdvancedFilterSet class, as well as filters of different nature will receive logical settings through a special field of the Meta class. Filters inherited from the Filter class will no longer be explicitly used for filtering with full-text search, so their manual application will no longer be possible.

Caveat

This change requires an implementation of the AdvancedDjangoObjectType class, because the standard DjangoObjectType class will ignore the unknown meta key.

from graphene_django_filter import AdvancedDjangoObjectType

class UserType(AdvancedDjangoObjectType):
    class Meta:'
       model = User
       fields = (
           'id',
           'name',
           'email',
       )
       filter_fields = {
           'name': ('exact',) 
       }
       full_text_search = {
           'trigram': {
                'name': ('exact', 'lt', 'gt',)
            },
            search_query: ('name', 'email')
            search_rank: {
                'fields': ('name', 'email')
                'lookups': ('exact', 'lt', 'gt',)
            }
       }

Metadata

Metadata

Assignees

Labels

designDesign improvement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions