2
2
import importlib
3
3
import inspect
4
4
import logging
5
+ import re
5
6
6
7
from django .apps .config import AppConfig
7
8
from django .apps .registry import apps
8
9
from django .conf import settings
9
10
from django .contrib .postgres .fields .jsonb import JSONField
10
11
from django .db .models .base import ModelBase
12
+ from django .db .models .fields import TextField , CharField
11
13
from django .db .models .fields .files import FileField
12
14
from django .template .defaultfilters import capfirst
13
15
from django .utils .translation import ugettext_lazy as _
14
16
import django_filters
15
- from django_filters .constants import ALL_FIELDS
17
+ from django_filters .constants import ALL_FIELDS , EMPTY_VALUES
16
18
from django_filters .filters import CharFilter
17
19
from django_filters .filterset import FilterSet
18
20
from django_filters .rest_framework .backends import DjangoFilterBackend
26
28
logger = logging .getLogger (__name__ )
27
29
28
30
31
+ class SplitStringCharFilter (django_filters .CharFilter ):
32
+ _re = re .compile (r'("[^"]+"| +|[^"]+)' )
33
+
34
+ def filter (self , qs , value ):
35
+ if value in EMPTY_VALUES :
36
+ return qs
37
+ if self .distinct :
38
+ qs = qs .distinct ()
39
+ lookup = '%s__%s' % (self .field_name , self .lookup_expr )
40
+
41
+ values = [value ]
42
+ if self .lookup_expr == 'icontains' :
43
+ if not '"' in value :
44
+ values = value .split (' ' )
45
+ else :
46
+ values = list (
47
+ filter (
48
+ lambda x : x and x != ' ' and x [0 ] != '"' ,
49
+ self ._re .findall (value )
50
+ )
51
+ ) + list (
52
+ map (
53
+ lambda x : x [1 :- 1 ],
54
+ filter (
55
+ lambda x : x and x [0 ] == '"' ,
56
+ self ._re .findall (value )
57
+ )
58
+ )
59
+ )
60
+
61
+ if not isinstance (values , list ):
62
+ values = [values ]
63
+ for v in values :
64
+ qs = self .get_method (qs )(** {lookup : v })
65
+ return qs
66
+
67
+
29
68
class ApiFilterSetMixin (FilterSet ):
30
69
31
70
o = CharFilter (method = 'filter_o' )
@@ -39,6 +78,12 @@ class Meta:
39
78
'lookup_expr' : 'exact' ,
40
79
},
41
80
},
81
+ CharField : {
82
+ 'filter_class' : SplitStringCharFilter ,
83
+ },
84
+ TextField : {
85
+ 'filter_class' : SplitStringCharFilter ,
86
+ },
42
87
JSONField : {
43
88
'filter_class' : django_filters .CharFilter ,
44
89
'extra' : lambda f : {
@@ -81,24 +126,24 @@ def get_keys_lookups(cl, sub_f):
81
126
r = []
82
127
for lk , lv in cl .items ():
83
128
84
- if lk == 'contained_by' :
129
+ if lk in ( 'contained_by' , 'trigram_similar' , 'unaccent' , 'search' ) :
85
130
continue
86
131
87
132
sflk = f'{ sub_f } { "__" if sub_f else "" } { lk } '
88
133
r .append (sflk )
89
134
90
- if hasattr (lv , 'class_lookups ' ):
91
- r += get_keys_lookups (lv .class_lookups , sflk )
135
+ if hasattr (lv , 'get_lookups ' ):
136
+ r += get_keys_lookups (lv .get_lookups () , sflk )
92
137
93
- if hasattr (lv , 'output_field' ) and hasattr (lv , 'output_field.class_lookups ' ):
138
+ if hasattr (lv , 'output_field' ) and hasattr (lv , 'output_field.get_lookups ' ):
94
139
r .append (f'{ sflk } { "__" if sflk else "" } range' )
95
140
96
141
r += get_keys_lookups (lv .output_field .class_lookups , sflk )
97
142
98
143
return r
99
144
100
145
fields [f_str ] = list (
101
- set (fields [f_str ] + get_keys_lookups (f .class_lookups , '' )))
146
+ set (fields [f_str ] + get_keys_lookups (f .get_lookups () , '' )))
102
147
103
148
# Remove excluded fields
104
149
exclude = exclude or []
0 commit comments