diff --git a/apis_ontology/filtersets.py b/apis_ontology/filtersets.py index 75288c8..6553921 100644 --- a/apis_ontology/filtersets.py +++ b/apis_ontology/filtersets.py @@ -103,29 +103,37 @@ def fuzzy_search_unaccent_trigram(queryset, fields, value): return trigram_search_filter(queryset, fields, tokens) -class GenericSearchFilterSet(AbstractEntityFilterSet): +class BaseEntityFilterSet(AbstractEntityFilterSet): + """ + Parent class for all entity model classes. + """ + + class Meta(AbstractEntityFilterSet.Meta): + filter_overrides = { + **AbstractEntityFilterSet.Meta.filter_overrides, + ArrayField: { + "filter_class": django_filters.MultipleChoiceFilter, + # "extra" attribute not working for fields with choices, see: + # https://github.com/carltongibson/django-filter/issues/1475 + "extra": lambda f: { + "lookup_expr": "icontains", + "widget": forms.SelectMultiple, + }, + }, + } + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - if "search" in self.filters: - self.filters.move_to_end("search", False) + if "custom_search" in self.filters: + self.filters.move_to_end("custom_search", False) -class PersonNameMixinFilterSet(GenericSearchFilterSet): - search = django_filters.CharFilter( - field_name=[ - "surname", - "forename", - "fallback_name", - "alternative_name", - ], - help_text=_("Suche in allen Namensfeldern"), - label=_("Suche: Namen"), - method=fuzzy_search_unaccent_trigram, - ) - +class TitlesSearch(django_filters.FilterSet): + """ + Search within title and subtitle fields. + """ -class TitlesMixinFilterSet(GenericSearchFilterSet): - search = django_filters.CharFilter( + custom_search = django_filters.CharFilter( field_name=[ "title", "subtitle", @@ -136,8 +144,16 @@ class TitlesMixinFilterSet(GenericSearchFilterSet): ) -class AlternativeNameMixinFilterSet(GenericSearchFilterSet): - search = django_filters.CharFilter( +class AlternativeNameSearch(django_filters.FilterSet): + """ + Search within name and alternative_name fields. + + With the exception of person-like entities (whose names are more complex), + the existence of the latter is assumed to be predicated on the former, + i.e. an entity cannot have an "alternative_name" without a "name". + """ + + custom_search = django_filters.CharFilter( field_name=[ "name", "alternative_name", @@ -148,39 +164,47 @@ class AlternativeNameMixinFilterSet(GenericSearchFilterSet): ) -class PersonFilterSet(PersonNameMixinFilterSet): +class PersonSearch(django_filters.FilterSet): + """ + Search within the various name fields used for persons and person-like + entities (like characters). + """ + + custom_search = django_filters.CharFilter( + field_name=[ + "surname", + "forename", + "fallback_name", + "alternative_name", + ], + help_text=_("Suche in allen Namensfeldern"), + label=_("Suche: Namen"), + method=fuzzy_search_unaccent_trigram, + ) + + +class PersonFilterSet(BaseEntityFilterSet, PersonSearch): pass -class CharacterFilterSet(PersonNameMixinFilterSet): +class CharacterFilterSet(BaseEntityFilterSet, PersonSearch): new_fictionality = django_filters.MultipleChoiceFilter( choices=Character.CharacterFictionality.choices, lookup_expr="icontains", ) - class Meta(PersonNameMixinFilterSet.Meta): + class Meta(BaseEntityFilterSet.Meta): fields = { "new_fictionality": ["icontains"], } - filter_overrides = { - ArrayField: { - "filter_class": django_filters.MultipleChoiceFilter, - # "extra" attribute not working for fields with choices, see: - # https://github.com/carltongibson/django-filter/issues/1475 - "extra": lambda f: { - "lookup_expr": "icontains", - "widget": forms.SelectMultiple, - }, - }, - } class VersionCharacterFilterSet(CharacterFilterSet): pass -class WorkFilterSet(TitlesMixinFilterSet): - search = django_filters.CharFilter( +class WorkFilterSet(BaseEntityFilterSet, TitlesSearch): + custom_search = django_filters.CharFilter( field_name=[ "title", "subtitle", @@ -237,28 +261,17 @@ class WorkFilterSet(TitlesMixinFilterSet): lookup_expr="icontains", ) - class Meta(TitlesMixinFilterSet.Meta): + class Meta(BaseEntityFilterSet.Meta): fields = { "temporal_order": ["icontains"], } - filter_overrides = { - ArrayField: { - "filter_class": django_filters.MultipleChoiceFilter, - # "extra" attribute not working for fields with choices, see: - # https://github.com/carltongibson/django-filter/issues/1475 - "extra": lambda f: { - "lookup_expr": "icontains", - "widget": forms.SelectMultiple, - }, - }, - } class VersionWorkFilterSet(WorkFilterSet): pass -class ExpressionFilterSet(TitlesMixinFilterSet): +class ExpressionFilterSet(BaseEntityFilterSet, TitlesSearch): new_edition_type = django_filters.MultipleChoiceFilter( choices=Expression.EditionTypes.choices, lookup_expr="icontains", @@ -269,45 +282,34 @@ class ExpressionFilterSet(TitlesMixinFilterSet): lookup_expr="icontains", ) - class Meta(TitlesMixinFilterSet.Meta): + class Meta(BaseEntityFilterSet.Meta): fields = { "language": ["icontains"], } - filter_overrides = { - ArrayField: { - "filter_class": django_filters.MultipleChoiceFilter, - # "extra" attribute not working for fields with choices, see: - # https://github.com/carltongibson/django-filter/issues/1475 - "extra": lambda f: { - "lookup_expr": "icontains", - "widget": forms.SelectMultiple, - }, - }, - } class VersionExpressionFilterSet(ExpressionFilterSet): pass -class OrganisationFilterSet(AlternativeNameMixinFilterSet): +class OrganisationFilterSet(BaseEntityFilterSet, AlternativeNameSearch): pass -class PlaceFilterSet(AlternativeNameMixinFilterSet): +class PlaceFilterSet(BaseEntityFilterSet, AlternativeNameSearch): pass -class ResearchPerspectiveFilterSet(AlternativeNameMixinFilterSet): +class ResearchPerspectiveFilterSet(BaseEntityFilterSet, AlternativeNameSearch): pass -class TopicFilterSet(AlternativeNameMixinFilterSet): +class TopicFilterSet(BaseEntityFilterSet, AlternativeNameSearch): pass -class WorkTypeFilterSet(AlternativeNameMixinFilterSet): - search = django_filters.CharFilter( +class WorkTypeFilterSet(BaseEntityFilterSet, AlternativeNameSearch): + custom_search = django_filters.CharFilter( field_name=[ "name", "name_plural",