1212
1313
1414@dataclass
15- class ParameterDefinition :
15+ class Parameter :
1616 param_name: str
1717 field_name: str
18+ view_name: str
1819 lookup: str
1920 negate: bool
2021 filter: 'Filter'
@@ -35,6 +36,7 @@ def __init__(
3536 default: Any = None,
3637 default_lookup: Optional[str] = None,
3738 description: Optional[str] = None,
39+ method: Optional[str] = None,
3840 _field_attrs: Optional[Dict[str, Any]] = None,
3941 _field_type: Optional[Type] = None,
4042 **kwargs,
@@ -49,6 +51,7 @@ def __init__(
4951 self.lookups = lookups or [self.default_lookup or 'exact']
5052 self.required = required
5153 self.exclude = exclude
54+ self.method = method
5255 self.field_attrs = {
5356 'description': description,
5457 'default': default or ... if (self.required and len(self.lookups) == 1) else None,
@@ -76,17 +79,18 @@ def _validate(self):
7679 if token not in self.lookups:
7780 raise ValueError(f"default_lookup '{self.default_lookup}' not in lookups {self.lookups}")
7881
79- def get_param_definitions(self) -> List[ParameterDefinition ]:
80- defs: List[ParameterDefinition ] = []
82+ def get_param_definitions(self) -> List[Parameter ]:
83+ defs: List[Parameter ] = []
8184 for lookup in self.lookups:
8285 display_token = f'not_{lookup}' if self.exclude else lookup
8386 annotation = LOOKUP_TYPES.get(lookup, self.field_type)
8487 param_name, negate_flag = self._resolve_param_name(lookup, display_token)
85- param_def = ParameterDefinition (
88+ param_def = Parameter (
8689 param_name=param_name,
8790 negate=negate_flag,
8891 annotation=Optional[annotation], # type:ignore
8992 filter=self,
93+ view_name=self.view_name,
9094 field_attrs=self.field_attrs,
9195 field_name=self.field_name,
9296 lookup=lookup,
@@ -153,7 +157,7 @@ def __new__(mcs, name, bases, namespace, **kwargs):
153157 if not isinstance(filters, list):
154158 raise ValueError('fields must be a list of Filter objects')
155159
156- param_map: Dict[str, ParameterDefinition ] = {}
160+ param_map: Dict[str, Parameter ] = {}
157161 for f in filters:
158162 if not isinstance(f, Filter):
159163 raise ValueError('All elements of fields must be Filter instances')
@@ -181,7 +185,7 @@ def _validate_model(self):
181185
182186 @classmethod
183187 def get_build(cls):
184- param_map: Dict[str, ParameterDefinition ] = getattr(cls, '_param_map', {})
188+ param_map: Dict[str, Parameter ] = getattr(cls, '_param_map', {})
185189
186190 def build(**kwargs):
187191 data = {k: v for k, v in kwargs.items() if v is not None}
@@ -201,19 +205,30 @@ def build(**kwargs):
201205 return build
202206
203207 def filter_queryset(self, queryset: QuerySet) -> QuerySet:
204- param_map: Dict[str, ParameterDefinition ] = getattr(self, '_param_map', {})
208+ param_map: Dict[str, Parameter ] = getattr(self, '_param_map', {})
205209
206210 for pname, raw_value in self.data.items():
207- info : Optional[ParameterDefinition ] = param_map.get(pname)
208- if not info or raw_value is None:
211+ parameter : Optional[Parameter ] = param_map.get(pname)
212+ if not parameter or raw_value is None:
209213 continue
210214
211- processed = info .filter._process_value(raw_value, info .lookup)
215+ processed = parameter .filter._process_value(raw_value, parameter .lookup)
212216 if processed is None:
213217 continue
214218
215- kwargs = LOOKUP_EXPRESSIONS[info.lookup](info.field_name, processed)
216- queryset = queryset.exclude(**kwargs) if info.negate else queryset.filter(**kwargs)
219+ if parameter.filter.method:
220+ method = getattr(self, parameter.filter.method, None)
221+ if method and callable(method):
222+ result = method(queryset=queryset, value=processed, parameter=parameter)
223+ if isinstance(result, QuerySet):
224+ queryset = result
225+ else:
226+ queryset = self.filter_by_parameter(queryset, processed, parameter)
227+ return queryset
228+
229+ def filter_by_parameter(self, queryset: QuerySet, value: Any, parameter: Parameter) -> QuerySet:
230+ kwargs = LOOKUP_EXPRESSIONS[parameter.lookup](parameter.field_name, value)
231+ queryset = queryset.exclude(**kwargs) if parameter.negate else queryset.filter(**kwargs)
217232 return queryset
218233
219234
0 commit comments