def test_filterset_fields_no_queryset(self): backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_fields = ['text', 'decimal', 'date'] filterset_class = backend.get_filterset_class(view, None) self.assertIsNone(filterset_class)
def test_get_operation_parameters_with_filterset_fields_list(self): backend = DjangoFilterBackend() fields = backend.get_schema_operation_parameters( FilterFieldsRootView()) fields = [f['name'] for f in fields] self.assertEqual(fields, ['decimal', 'date'])
def test_filterset_fields(self): backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_fields = ['text', 'decimal', 'date'] queryset = FilterableItem.objects.all() filterset_class = backend.get_filterset_class(view, queryset) self.assertEqual(filterset_class._meta.fields, view.filterset_fields)
def test_filterset_fields_malformed(self): backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_fields = ['non_existent'] queryset = FilterableItem.objects.all() msg = "'Meta.fields' contains fields that are not defined on this FilterSet: non_existent" with self.assertRaisesMessage(TypeError, msg): backend.get_filterset_class(view, queryset)
def test_filterset_fields_malformed(self): backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_fields = ['non_existent'] queryset = FilterableItem.objects.all() msg = "'Meta.fields' must not contain non-model field names: non_existent" with self.assertRaisesMessage(TypeError, msg): backend.get_filterset_class(view, queryset)
def test_malformed_filterset_fields(self): # Malformed filter fields should raise an exception class View(FilterFieldsRootView): filterset_fields = ['non_existent'] backend = DjangoFilterBackend() msg = "'Meta.fields' must not contain non-model field names: non_existent" with self.assertRaisesMessage(TypeError, msg): backend.get_schema_fields(View())
def test_fields_with_filter_class(self): backend = DjangoFilterBackend() fields = backend.get_schema_fields(FilterClassRootView()) schemas = [f.schema for f in fields] fields = [f.name for f in fields] self.assertEqual(fields, ['text', 'decimal', 'date']) self.assertIsInstance(schemas[0], compat.coreschema.String) self.assertIsInstance(schemas[1], compat.coreschema.Number) self.assertIsInstance(schemas[2], compat.coreschema.String)
def test_malformed_filterset_fields(self): # Malformed filter fields should raise an exception class View(FilterFieldsRootView): filterset_fields = ['non_existent'] backend = DjangoFilterBackend() msg = "'Meta.fields' contains fields that are not defined on this FilterSet: non_existent" with self.assertRaisesMessage(TypeError, msg): backend.get_schema_fields(View())
def test_filterset_class_no_meta(self): class Filter(FilterSet): pass backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_class = Filter queryset = FilterableItem.objects.all() filterset_class = backend.get_filterset_class(view, queryset) self.assertIs(filterset_class, Filter)
def test_fields_with_filter_fields_dict(self): class DictFilterFieldsRootView(FilterFieldsRootView): filter_fields = { 'decimal': ['exact', 'lt', 'gt'], } backend = DjangoFilterBackend() fields = backend.get_schema_fields(DictFilterFieldsRootView()) fields = [f.name for f in fields] self.assertEqual(fields, ['decimal', 'decimal__lt', 'decimal__gt'])
def test_filter_fields_list_with_bad_get_queryset(self): """ See: * https://github.com/carltongibson/django-filter/issues/551 """ class BadGetQuerySetView(FilterFieldsRootView): def get_queryset(self): raise AttributeError("I don't have that") backend = DjangoFilterBackend() fields = backend.get_schema_fields(BadGetQuerySetView()) self.assertEqual(fields, [], "get_schema_fields should handle AttributeError")
def test_filterset_class_no_queryset(self): class Filter(FilterSet): class Meta: model = FilterableItem fields = '__all__' backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_class = Filter filterset_class = backend.get_filterset_class(view, None) self.assertIs(filterset_class, Filter)
def test_filterset_class(self): class Filter(FilterSet): class Meta: model = FilterableItem fields = '__all__' backend = DjangoFilterBackend() view = FilterableItemView() view.filterset_class = Filter queryset = FilterableItem.objects.all() filterset_class = backend.get_filterset_class(view, queryset) self.assertIs(filterset_class, Filter)
def test_get_operation_parameters_with_filterset_fields_list_with_choices( self): backend = DjangoFilterBackend() fields = backend.get_schema_operation_parameters(CategoryItemView()) self.assertEqual(fields, [{ 'name': 'category', 'required': False, 'in': 'query', 'description': 'category', 'schema': { 'type': 'string', 'enum': ['home', 'office'] }, }])
def test_filter_class(self): expected = "`View.filter_class` attribute should be renamed `filterset_class`. " \ "See: https://django-filter.readthedocs.io/en/master/guide/migration.html" with warnings.catch_warnings(record=True) as recorded: warnings.simplefilter('always') class View(generics.ListCreateAPIView): filter_class = None view = View() backend = DjangoFilterBackend() backend.get_filterset_class(view, None) message = str(recorded.pop().message) self.assertEqual(message, expected) self.assertEqual(len(recorded), 0)
def get_django_filter_schema_operation_parameters( self, filter_backend: DjangoFilterBackend) -> typing.List[OpenAPISchema]: queryset = self.get_view_queryset() filterset_class = filter_backend.get_filterset_class( self.view, queryset) if not filterset_class: return [] parameters = [] for field_name, field in filterset_class.base_filters.items(): parameter = { 'name': field_name, 'required': field.extra['required'], 'in': 'query', 'description': self.get_verbose_filter_field_description( filterset_class, field), 'schema': get_filter_schema(filter_field=field, filter_map=self.filter_map), } parameters.append(parameter) return parameters
def get(self, request, post_pk): instance = get_object_or_404(Post, pk=post_pk) queryset = DjangoFilterBackend().filter_queryset( request, instance.comments, self) serializer = self.serializer_class(queryset, many=True, context={'request': request}) return Response(serializer.data)
def tests_field_with_request_callable(self): def qs(request): # users expect a valid request object to be provided which cannot # be guaranteed during schema generation. self.fail("callable queryset should not be invoked during schema generation") class F(SeveralFieldsFilter): f = filters.ModelChoiceFilter(queryset=qs) class View(FilterClassRootView): filter_class = F view = View() view.request = factory.get('/') backend = DjangoFilterBackend() fields = backend.get_schema_fields(view) fields = [f.name for f in fields] self.assertEqual(fields, ['text', 'decimal', 'date', 'f'])
def test_field_required(self): class RequiredFieldsFilter(SeveralFieldsFilter): required_text = filters.CharFilter(required=True) class Meta(SeveralFieldsFilter.Meta): fields = SeveralFieldsFilter.Meta.fields + ['required_text'] class FilterClassWithRequiredFieldsView(FilterClassRootView): filterset_class = RequiredFieldsFilter backend = DjangoFilterBackend() fields = backend.get_schema_fields(FilterClassWithRequiredFieldsView()) required = [f.required for f in fields] fields = [f.name for f in fields] self.assertEqual(fields, ['text', 'decimal', 'date', 'required_text']) self.assertFalse(required[0]) self.assertFalse(required[1]) self.assertFalse(required[2]) self.assertTrue(required[3])
def test_filter_fields_list_with_bad_get_queryset(self): """ See: * https://github.com/carltongibson/django-filter/issues/551 """ class BadGetQuerySetView(FilterFieldsRootView): def get_queryset(self): raise AttributeError("I don't have that") backend = DjangoFilterBackend() with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") fields = backend.get_schema_fields(BadGetQuerySetView()) self.assertEqual(fields, [], "get_schema_fields should handle AttributeError") warning = "{} is not compatible with schema generation".format(BadGetQuerySetView) self.assertEqual(len(w), 1) self.assertEqual(str(w[0].message), warning)
def test_errors(self): class F(FilterSet): class Meta: model = Article fields = ['id', 'author', 'name'] view = FilterFieldsRootView() backend = DjangoFilterBackend() request = factory.get('/?id=foo&author=bar&name=baz') request = view.initialize_request(request) queryset = Article.objects.all() view.filterset_class = F with self.assertRaises(serializers.ValidationError) as exc: backend.filter_queryset(request, queryset, view) # test output, does not include error code self.assertDictEqual(exc.exception.detail, { 'id': ['Enter a number.'], 'author': ['Select a valid choice. That choice is not one of the available choices.'], })
def __new__(cls, *args, **kwargs): assert django_filters, 'Using DjangoFilterBackend, but django-filter is not installed' assert django_filters.VERSION >= ( 0, 15, 3), 'django-filter 0.15.3 and above is required' warnings.warn( "The built in 'rest_framework.filters.DjangoFilterBackend' is pending deprecation. " "You should use 'django_filters.rest_framework.DjangoFilterBackend' instead.", PendingDeprecationWarning) from django_filters.rest_framework import DjangoFilterBackend return DjangoFilterBackend(*args, **kwargs)
def aggregate(self, request): """ Aggregate field values based on start/end time. Returns the unique values shared across all FITS files for site, telescope, instrument, filter, proposal, and obstype. """ # TODO: This should be removed after a while, it is just here for temporary API compatibility FIELD_MAPPING = { 'SITEID': 'site_id', 'TELID': 'telescope_id', 'FILTER': 'primary_optical_element', 'INSTRUME': 'instrument_id', 'OBSTYPE': 'configuration_type', 'PROPID': 'proposal_id' } fields = ('site_id', 'telescope_id', 'primary_optical_element', 'instrument_id', 'configuration_type', 'proposal_id') aggregate_field = request.GET.get('aggregate_field', 'ALL') if aggregate_field in FIELD_MAPPING: aggregate_field = FIELD_MAPPING[aggregate_field] if aggregate_field != 'ALL' and aggregate_field not in fields: return Response( 'Invalid aggregate_field. Valid fields are {}'.format( ', '.join(fields)), status=status.HTTP_400_BAD_REQUEST) query_filters = {} for k in FIELD_MAPPING.keys(): if k in request.GET: query_filters[FIELD_MAPPING[k]] = request.GET[k] for k in fields: if k in request.GET: query_filters[k] = request.GET[k] if 'start' in request.GET: query_filters['start'] = parse(request.GET['start']).replace( tzinfo=UTC, second=0, microsecond=0) if 'end' in request.GET: query_filters['end'] = parse(request.GET['end']).replace( tzinfo=UTC, second=0, microsecond=0) cache_hash = blake2s( repr(frozenset(list(query_filters.items()) + [aggregate_field])).encode()).hexdigest() response_dict = cache.get(cache_hash) if not response_dict: qs = Frame.objects.all() qs = DjangoFilterBackend().filter_queryset(request, qs, view=self) sites = self._get_aggregate_values(qs, query_filters, 'site_id', aggregate_field) telescopes = self._get_aggregate_values(qs, query_filters, 'telescope_id', aggregate_field) filters = self._get_aggregate_values(qs, query_filters, 'primary_optical_element', aggregate_field) instruments = self._get_aggregate_values(qs, query_filters, 'instrument_id', aggregate_field) obstypes = self._get_aggregate_values(qs, query_filters, 'configuration_type', aggregate_field) proposals = self._get_aggregate_values( qs.filter(public_date__lte=timezone.now()), query_filters, 'proposal_id', aggregate_field) response_dict = { 'sites': sites, 'telescopes': telescopes, 'filters': filters, 'instruments': instruments, 'obstypes': obstypes, 'proposals': proposals } cache.set(cache_hash, response_dict, 60 * 60) response_serializer = self.get_response_serializer(response_dict) return Response(response_serializer.data)
def test_fields_with_filter_fields_list(self): backend = DjangoFilterBackend() fields = backend.get_schema_fields(FilterFieldsRootView()) fields = [f.name for f in fields] self.assertEqual(fields, ['decimal', 'date'])
def setUpTestData(cls): cls.backend = DjangoFilterBackend() cls.backend.get_filterset_class = lambda x, y: None