2
2
from apis_core .generic .filtersets import django_filters
3
3
from apis_core .relations .filtersets import RelationFilterSet
4
4
from django .db import models
5
+ from django .db .models import Q , CharField , TextField
5
6
from apis_ontology .forms import RelationFilterSetForm , EntityFilterSetForm
7
+ from django .contrib .postgres .search import SearchVector , SearchQuery
8
+
9
+
10
+ def generic_search_filter (queryset , name , value , fields = None ):
11
+ """
12
+ A generic filter that searches across specified fields using unaccent__icontains with OR logic.
13
+
14
+ Priority for fields selection:
15
+ 1. Explicitly provided fields parameter
16
+ 2. _default_search_fields attribute on the model
17
+ 3. All CharField and TextField fields from the model
18
+
19
+ Args:
20
+ queryset: The queryset to filter
21
+ name: The name of the filter (not used)
22
+ value: The search value
23
+ fields: Optional list of specific field names to search in
24
+
25
+ Returns:
26
+ Filtered queryset
27
+ """
28
+ if not value :
29
+ return queryset
30
+
31
+ # If no fields specified, check for _default_search_fields or use all text fields
32
+ if fields is None :
33
+ model = queryset .model
34
+
35
+ # Check if model has _default_search_fields attribute
36
+ if hasattr (model , "_default_search_fields" ):
37
+ fields = model ._default_search_fields
38
+ else :
39
+ # Fall back to all CharField and TextField fields
40
+ fields = []
41
+ for field in model ._meta .get_fields ():
42
+ if isinstance (field , (CharField , TextField )) and not field .primary_key :
43
+ fields .append (field .name )
44
+
45
+ # Build Q objects for each field with OR logic
46
+ q_objects = Q ()
47
+ for field in fields :
48
+ q_objects |= Q (** {f"{ field } __unaccent__icontains" : value })
49
+
50
+ return queryset .filter (q_objects )
6
51
7
52
8
53
class NomanslandMixinFilterSet (AbstractEntityFilterSet ):
@@ -28,17 +73,30 @@ class Meta(AbstractEntityFilterSet.Meta):
28
73
models .CharField : {
29
74
"filter_class" : django_filters .CharFilter ,
30
75
"extra" : lambda f : {
31
- "lookup_expr" : "icontains " ,
76
+ "lookup_expr" : "unaccent__icontains " ,
32
77
},
33
78
},
34
79
models .TextField : {
35
80
"filter_class" : django_filters .CharFilter ,
36
81
"extra" : lambda f : {
37
- "lookup_expr" : "icontains " ,
82
+ "lookup_expr" : "unaccent__icontains " ,
38
83
},
39
84
},
40
85
}
41
86
87
+ def __init__ (self , * args , ** kwargs ):
88
+ super ().__init__ (* args , ** kwargs )
89
+ for filter in self .filters .values ():
90
+ if (
91
+ hasattr (filter , "label" )
92
+ and filter .label
93
+ and "unaccent contains" in filter .label
94
+ ):
95
+ filter .label = filter .label .replace ("unaccent contains" , "" )
96
+ self .filters ["search" ] = django_filters .CharFilter (
97
+ method = generic_search_filter , label = "Search"
98
+ )
99
+
42
100
43
101
class NomanslandRelationMixinFilterSet (RelationFilterSet ):
44
102
class Meta (RelationFilterSet .Meta ):
@@ -67,3 +125,12 @@ class Meta(RelationFilterSet.Meta):
67
125
},
68
126
},
69
127
}
128
+
129
+ def __init__ (self , * args , ** kwargs ):
130
+ super ().__init__ (* args , ** kwargs )
131
+ for filter in self .filters .values ():
132
+ if hasattr (filter , "label" ) and filter .label and "contains" in filter .label :
133
+ filter .label = filter .label .replace ("contains" , "" )
134
+ self .filters ["search" ] = django_filters .CharFilter (
135
+ method = generic_search_filter , label = "Search"
136
+ )
0 commit comments