11"""Helper to create sqlalchemy filters according to filter querystring parameter"""
2+ import inspect
23import logging
34from typing import (
45 Any ,
@@ -133,10 +134,10 @@ def create_filter(self, schema_field: ModelField, model_column, operator, value)
133134 pydantic_types , userspace_types = self ._separate_types (types )
134135
135136 if pydantic_types :
137+ func = self ._cast_value_with_pydantic
136138 if isinstance (value , list ):
137- clear_value , errors = self ._cast_iterable_with_pydantic (pydantic_types , value )
138- else :
139- clear_value , errors = self ._cast_value_with_pydantic (pydantic_types , value )
139+ func = self ._cast_iterable_with_pydantic
140+ clear_value , errors = func (pydantic_types , value , schema_field )
140141
141142 if clear_value is None and userspace_types :
142143 log .warning ("Filtering by user type values is not properly tested yet. Use this on your own risk." )
@@ -151,7 +152,10 @@ def create_filter(self, schema_field: ModelField, model_column, operator, value)
151152
152153 # Если None, при этом поле обязательное (среди типов в аннотации нет None, то кидаем ошибку)
153154 if clear_value is None and not can_be_none :
154- raise InvalidType (detail = ", " .join (errors ))
155+ raise InvalidType (
156+ detail = ", " .join (errors ),
157+ pointer = schema_field .name ,
158+ )
155159
156160 return getattr (model_column , self .operator )(clear_value )
157161
@@ -179,32 +183,65 @@ def _separate_types(self, types: List[Type]) -> Tuple[List[Type], List[Type]]:
179183 ]
180184 return pydantic_types , userspace_types
181185
186+ def _validator_requires_model_field (self , validator : Callable ) -> bool :
187+ """
188+ Check if validator accepts the `field` param
189+
190+ :param validator:
191+ :return:
192+ """
193+ signature = inspect .signature (validator )
194+ parameters = signature .parameters
195+
196+ if "field" not in parameters :
197+ return False
198+
199+ field_param = parameters ["field" ]
200+ field_type = field_param .annotation
201+
202+ return field_type == "ModelField" or field_type is ModelField
203+
182204 def _cast_value_with_pydantic (
183205 self ,
184206 types : List [Type ],
185207 value : Any ,
208+ schema_field : ModelField ,
186209 ) -> Tuple [Optional [Any ], List [str ]]:
187210 result_value , errors = None , []
188211
189212 for type_to_cast in types :
190213 for validator in find_validators (type_to_cast , BaseConfig ):
214+ args = [value ]
215+ # TODO: some other way to get all the validator's dependencies?
216+ if self ._validator_requires_model_field (validator ):
217+ args .append (schema_field )
191218 try :
192- result_value = validator (value )
193- return result_value , errors
219+ result_value = validator (* args )
194220 except Exception as ex :
195221 errors .append (str (ex ))
222+ else :
223+ return result_value , errors
196224
197225 return None , errors
198226
199- def _cast_iterable_with_pydantic (self , types : List [Type ], values : List ) -> Tuple [List , List [str ]]:
227+ def _cast_iterable_with_pydantic (
228+ self ,
229+ types : List [Type ],
230+ values : List ,
231+ schema_field : ModelField ,
232+ ) -> Tuple [List , List [str ]]:
200233 type_cast_failed = False
201234 failed_values = []
202235
203236 result_values : List [Any ] = []
204237 errors : List [str ] = []
205238
206239 for value in values :
207- casted_value , cast_errors = self ._cast_value_with_pydantic (types , value )
240+ casted_value , cast_errors = self ._cast_value_with_pydantic (
241+ types ,
242+ value ,
243+ schema_field ,
244+ )
208245 errors .extend (cast_errors )
209246
210247 if casted_value is None :
@@ -217,7 +254,7 @@ def _cast_iterable_with_pydantic(self, types: List[Type], values: List) -> Tuple
217254
218255 if type_cast_failed :
219256 msg = f"Can't parse items { failed_values } of value { values } "
220- raise InvalidFilters (msg )
257+ raise InvalidFilters (msg , pointer = schema_field . name )
221258
222259 return result_values , errors
223260
0 commit comments