def _get_requested_filters(self, **kwargs): """ Convert 'filters' query params into a dict that can be passed to Q. Returns a dict with two fields, 'include' and 'exclude', which can be used like: result = self._get_requested_filters() q = Q(**result['_include'] & ~Q(**result['_exclude']) """ filters_map = kwargs.get('filters_map') view = getattr(self, 'view', None) if view: serializer_class = view.get_serializer_class() serializer = serializer_class() if not filters_map: filters_map = view.get_request_feature(view.FILTER) else: serializer = None out = TreeMap() for key, value in six.iteritems(filters_map): # Inclusion or exclusion? if key[0] == '-': key = key[1:] category = '_exclude' else: category = '_include' # for relational filters, separate out relation path part if '|' in key: rel, key = key.split('|') rel = rel.split('.') else: rel = None terms = key.split('.') # Last part could be operator, e.g. "events.capacity.gte" if len(terms) > 1 and terms[-1] in self.VALID_FILTER_OPERATORS: operator = terms.pop() else: operator = None # All operators except 'range' and 'in' should have one value if operator == 'range': value = value[:2] if value[0] == '': operator = 'lte' value = value[1] elif value[1] == '': operator = 'gte' value = value[0] elif operator == 'in': # no-op: i.e. accept `value` as an arbitrarily long list pass elif operator in self.VALID_FILTER_OPERATORS: value = value[0] if (operator == 'isnull' and isinstance(value, six.string_types)): value = is_truthy(value) elif operator == 'eq': operator = None if serializer: s = serializer if rel: # get related serializer model_fields, serializer_fields = serializer.resolve(rel) s = serializer_fields[-1] s = getattr(s, 'serializer', s) rel = [Meta.get_query_name(f) for f in model_fields] # perform model-field resolution model_fields, serializer_fields = s.resolve(terms) field = serializer_fields[-1] if serializer_fields else None # if the field is a boolean, # coerce the value if field and isinstance( field, (serializers.BooleanField, serializers.NullBooleanField)): value = is_truthy(value) key = '__'.join([Meta.get_query_name(f) for f in model_fields]) else: key = '__'.join(terms) if operator: key += '__%s' % operator # insert into output tree path = rel if rel else [] path += [category, key] out.insert(path, value) return out
def _get_requested_filters(self, **kwargs): """ Convert 'filters' query params into a dict that can be passed to Q. Returns a dict with two fields, 'include' and 'exclude', which can be used like: result = self._get_requested_filters() q = Q(**result['include'] & ~Q(**result['exclude']) """ filters_map = (kwargs.get('filters_map') or self.view.get_request_feature(self.view.FILTER)) out = TreeMap() for spec, value in six.iteritems(filters_map): # Inclusion or exclusion? if spec[0] == '-': spec = spec[1:] inex = '_exclude' else: inex = '_include' # for relational filters, separate out relation path part if '|' in spec: rel, spec = spec.split('|') rel = rel.split('.') else: rel = None parts = spec.split('.') # Last part could be operator, e.g. "events.capacity.gte" if len(parts) > 1 and parts[-1] in self.VALID_FILTER_OPERATORS: operator = parts.pop() else: operator = None # All operators except 'range' and 'in' should have one value if operator == 'range': value = value[:2] elif operator == 'in': # no-op: i.e. accept `value` as an arbitrarily long list pass elif operator in self.VALID_FILTER_OPERATORS: value = value[0] if (operator == 'isnull' and isinstance(value, six.string_types)): value = is_truthy(value) elif operator == 'eq': operator = None node = FilterNode(parts, operator, value) # insert into output tree path = rel if rel else [] path += [inex, node.key] out.insert(path, node) return out
def _extract_filters(self, **kwargs): """ Convert 'filters' query params into a dict that can be passed to Q. Returns a dict with two fields, 'include' and 'exclude', which can be used like: result = self._extract_filters() q = Q(**result['include'] & ~Q(**result['exclude']) """ filters_map = ( kwargs.get('filters_map') or self.view.get_request_feature(self.view.FILTER) ) out = TreeMap() for spec, value in six.iteritems(filters_map): # Inclusion or exclusion? if spec[0] == '-': spec = spec[1:] inex = '_exclude' else: inex = '_include' # for relational filters, separate out relation path part if '|' in spec: rel, spec = spec.split('|') rel = rel.split('.') else: rel = None parts = spec.split('.') # Last part could be operator, e.g. "events.capacity.gte" if len(parts) > 1 and parts[-1] in self.VALID_FILTER_OPERATORS: operator = parts.pop() else: operator = None # All operators except 'range' and 'in' should have one value if operator == 'range': value = value[:2] elif operator == 'in': # no-op: i.e. accept `value` as an arbitrarily long list pass elif operator in self.VALID_FILTER_OPERATORS: value = value[0] if ( operator == 'isnull' and isinstance(value, six.string_types) ): value = value.lower() not in self.FALSEY_STRINGS elif operator == 'eq': operator = None node = FilterNode(parts, operator, value) # insert into output tree path = rel if rel else [] path += [inex, node.key] out.insert(path, node) return out