def test_searching_q_ok(value, db_lookup, db_value): cls = BooksFilterClass(book_qs) for v in (value, '"{}"'.format(value)): like_q = cls.build_q_for_filter(FilterArgs('title', SearchOperators.LIKE, v)) assert like_q.children[0] == ('title__{}'.format(db_lookup), db_value) i_like_q = cls.build_q_for_filter(FilterArgs('title', SearchOperators.I_LIKE, value)) assert i_like_q.children[0] == ('title__i{}'.format(db_lookup), db_value)
def listing(self, args): # Django __in lookup is not used, because of null() values operation, prop = self._get_value(args[0]), self._get_value(args[1]) f_op = ComparisonOperators.EQ if operation == ListOperators.IN else ComparisonOperators.NE q = Q() for value_tree in args[2:]: value = self._get_value(value_tree) if isinstance(value, Q): if f_op == ComparisonOperators.EQ: field_q = value else: field_q = ~value else: field_q = self._filter_cls_instance.build_q_for_filter( FilterArgs( prop, f_op, value, list_operator=operation, )) if operation == ListOperators.IN: q |= field_q else: q &= field_q self._filtered_props.add(prop) return q
def _build_q_for_search(self, operator, str_value): if operator != ComparisonOperators.EQ: raise RQLFilterParsingError( details={ 'error': 'Bad search filter: {}.'.format(operator), }) unquoted_value = self.remove_quotes(str_value) if not unquoted_value: return Q() if not unquoted_value.startswith(RQL_ANY_SYMBOL): unquoted_value = '*' + unquoted_value if not unquoted_value.endswith(RQL_ANY_SYMBOL): unquoted_value += '*' q = self._build_q_for_extended_search(unquoted_value) for filter_name in self.search_filters: q |= self.build_q_for_filter( FilterArgs( filter_name, SearchOperators.I_LIKE, unquoted_value, )) return q
def searching(self, args): # like, ilike operation, prop, val = tuple( self._get_value(args[index]) for index in range(3)) self._filtered_props.add(prop) return self._filter_cls_instance.build_q_for_filter( FilterArgs(prop, operation, val))
def test_custom_filter_ok(): class CustomCls(BooksFilterClass): def build_q_for_custom_filter(self, *args, **kwargs): return Q(id__gte=2) filter_cls = CustomCls(book_qs) q = filter_cls.build_q_for_filter(FilterArgs('custom_filter', SearchOperators.I_LIKE, 'value')) books = [Book.objects.create() for _ in range(2)] assert list(book_qs.filter(q)) == [books[1]]
def searching(self, args): # like, ilike operation, prop, val = tuple( self._get_value(args[index]) for index in range(3)) filter_args = FilterArgs(prop, operation, val, namespace=self._get_current_namespace()) self._filtered_props.add(filter_args.filter_name) return self._filter_cls_instance.build_q_for_filter(filter_args)
def comp(self, args): prop, operation, value = self._extract_comparison(args) if isinstance(value, Q): if operation == ComparisonOperators.EQ: return value else: return ~value filter_args = FilterArgs(prop, operation, value, namespace=self._get_current_namespace()) self._filtered_props.add(filter_args.filter_name) return self._filter_cls_instance.build_q_for_filter(filter_args)
def filter_field(filter_name, operator, value): filter_cls = BooksFilterClass(book_qs) q = filter_cls.build_q_for_filter( FilterArgs(filter_name, operator, str(value))) return list(book_qs.filter(q))
def build_q_for_filter(self, data): """ Django Q() builder for extracted from query RQL expression. In general, this method should not be overridden. :param FilterArgs data: Prepared filter data for custom filtering. :rtype: django.db.models.Q """ filter_name, operator, str_value = data.filter_name, data.operator, data.str_value list_operator = data.list_operator if filter_name == RQL_SEARCH_PARAM: return self._build_q_for_search(operator, str_value) base_item = self.get_filter_base_item(filter_name) if not base_item: return Q() if base_item.get('distinct'): self._is_distinct = True filter_item = self.filters[filter_name] available_lookups = base_item.get('lookups', set()) if list_operator: list_filter_lookup = FilterLookups.IN \ if list_operator == ListOperators.IN \ else FilterLookups.OUT if list_filter_lookup not in available_lookups: raise RQLFilterLookupError(**self._get_error_details( filter_name, list_filter_lookup, str_value, )) null_values = base_item.get('null_values', set()) filter_lookup = self._get_filter_lookup( filter_name, operator, str_value, available_lookups, null_values, ) django_lookup = self._get_django_lookup(filter_lookup, str_value, null_values) if base_item.get('custom'): return self.build_q_for_custom_filter( FilterArgs( filter_name, operator, str_value, list_operator=list_operator, filter_lookup=filter_lookup, django_lookup=django_lookup, )) django_field = base_item['field'] use_repr = base_item.get('use_repr', False) typed_value = self._get_typed_value( filter_name, filter_lookup, str_value, django_field, use_repr, null_values, django_lookup, ) if not isinstance(filter_item, iterable_types): return self._build_django_q(filter_item, django_lookup, filter_lookup, typed_value) # filter has different DB field 'sources' q = Q() for item in filter_item: item_q = self._build_django_q(item, django_lookup, filter_lookup, typed_value) if filter_lookup == FilterLookups.NE: q &= item_q else: q |= item_q return q
def comp(self, args): prop, operation, value = self._extract_comparison(args) self._filtered_props.add(prop) return self._filter_cls_instance.build_q_for_filter( FilterArgs(prop, operation, value))