# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.conf.urls import url from django.test import TestCase from django.test import override_settings from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import FilterSet from rest_framework import filters from rest_framework.generics import ListAPIView from rest_framework.permissions import AllowAny from rest_framework.reverse import reverse from drf_tweaks import serializers from drf_tweaks.autofilter import autofilter from tests.models import SampleModel from tests.models import SampleModelForAutofilter class SampleModelForAutofilterSerializerVer1(serializers.ModelSerializer): class Meta: model = SampleModelForAutofilter fields = ["id", "fk", "non_indexed_fk", "indexed_int", "non_indexed_int", "indexed_char", "non_indexed_char", "indexed_text", "non_indexed_text", "indexed_url", "non_indexed_url", "indexed_email", "non_indexed_email", "nullable_field", "some_property", "unique_text"] class SampleModelForAutofilterSerializerVer2(serializers.ModelSerializer): class Meta: model = SampleModelForAutofilter fields = ["id", "fk", "non_indexed_fk", "indexed_int", "non_indexed_int", "indexed_char", "non_indexed_char"] class SampleFilterClass(FilterSet): class Meta: model = SampleModelForAutofilter fields = ("non_indexed_email", ) class SampleFilterClassV2(FilterSet): class Meta: model = SampleModelForAutofilter fields = {"non_indexed_email": ["exact"]} @autofilter() class SampleApiV1(ListAPIView): queryset = SampleModelForAutofilter.objects.all() permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 filter_backends = (filters.OrderingFilter,) @autofilter() class SampleApiV2(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer2 queryset = SampleModelForAutofilter.objects.all() @autofilter(extra_ordering=("non_indexed_fk", ), extra_filter=("non_indexed_int", "some_property")) class SampleApiV3(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 queryset = SampleModelForAutofilter.objects.all() ordering_fields = ("non_indexed_char", ) filter_fields = ("non_indexed_email", ) @autofilter(extra_filter=("non_indexed_int", )) class SampleApiV4(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 queryset = SampleModelForAutofilter.objects.all() filter_class = SampleFilterClass @autofilter() class SampleApiV5(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 queryset = SampleModelForAutofilter.objects.all() filter_class = SampleFilterClass @autofilter() class SampleApiV6(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 queryset = SampleModelForAutofilter.objects.all() filter_class = SampleFilterClassV2 urlpatterns = [ url(r"^autofilter/$", SampleApiV1.as_view(), name="autofilter_test"), url(r"^autofilter-with-class/$", SampleApiV1.as_view(), name="autofilter_with_class_test"), ] @override_settings(ROOT_URLCONF="tests.test_autofilter") class TestAutoFilter(TestCase): def setUp(self): self.sm1 = SampleModel.objects.create(a="a", b="b") self.sm2 = SampleModel.objects.create(a="b", b="c") self.smfa1 = SampleModelForAutofilter.objects.create( fk=self.sm1, non_indexed_fk=self.sm1, indexed_int=1, non_indexed_int=1, indexed_char="abc", non_indexed_char="cde", indexed_text="abcd", non_indexed_text="cdef", indexed_url="https://www.google.com/?q=1", non_indexed_url="https://www.google.com/?q=2", indexed_email="abc@gmail.com", non_indexed_email="cde@gmail.com", nullable_field=1, unique_text="a", ) self.smfa2 = SampleModelForAutofilter.objects.create( fk=self.sm2, non_indexed_fk=self.sm2, indexed_int=2, non_indexed_int=2, indexed_char="fgh", non_indexed_char="ijk", indexed_text="lorem", non_indexed_text="lorem 2", indexed_url="https://www.google.com/?q=3", non_indexed_url="https://www.google.com/?q=4", indexed_email="fgh@gmail.com", non_indexed_email="ijk@gmail.com", unique_text="b", ) def test_adding_filter_backends(self): self.assertIn(filters.OrderingFilter, SampleApiV1.filter_backends) self.assertIn(DjangoFilterBackend, SampleApiV1.filter_backends) def test_adding_filter_backends_with_existing(self): self.assertIn(filters.OrderingFilter, SampleApiV2.filter_backends) self.assertIn(DjangoFilterBackend, SampleApiV2.filter_backends) def test_adding_ordering_fields(self): self.assertEqual(set(SampleApiV1.ordering_fields), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "nullable_field", "unique_text"}) self.assertEqual(set(SampleApiV2.ordering_fields), {"id", "fk", "indexed_int", "indexed_char"}) def test_adding_ordering_fields_with_extra_and_explicit(self): self.assertEqual(set(SampleApiV3.ordering_fields), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "non_indexed_fk", "non_indexed_char", "nullable_field", "unique_text"}) def test_adding_filter_fields(self): self.assertEqual(set(SampleApiV1.filter_fields.keys()), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "nullable_field", "unique_text"}) self.assertEqual(set(SampleApiV2.filter_fields.keys()), {"id", "fk", "indexed_int", "indexed_char"}) for key in ("id", "fk", "indexed_int"): self.assertEqual(SampleApiV1.filter_fields[key], ["exact", "gt", "gte", "lt", "lte", "in", "isnull"]) for key in ("indexed_char", "indexed_text", "indexed_url", "indexed_email", "unique_text"): self.assertEqual( SampleApiV1.filter_fields[key], ["exact", "gt", "gte", "lt", "lte", "in", "isnull", "icontains", "istartswith"]) def test_adding_filter_fields_with_extra_and_explicit(self): self.assertEqual(set(SampleApiV3.filter_fields.keys()), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "non_indexed_int", "non_indexed_email", "nullable_field", "unique_text"}) def test_adding_filter_fields_with_extra_andfilter_class(self): self.assertNotEqual(SampleApiV4.filter_class, SampleApiV5.filter_class) self.assertNotEqual(SampleApiV4.filter_class.Meta, SampleApiV5.filter_class.Meta) self.assertEqual(set(SampleApiV4.filter_class.Meta.fields.keys()), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "non_indexed_int", "non_indexed_email", "nullable_field", "unique_text"}) self.assertEqual(set(SampleApiV5.filter_class.Meta.fields.keys()), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "non_indexed_email", "nullable_field", "unique_text"}) self.assertEqual(set(SampleApiV6.filter_class.Meta.fields.keys()), {"id", "fk", "indexed_int", "indexed_char", "indexed_text", "indexed_url", "indexed_email", "non_indexed_email", "nullable_field", "unique_text"}) def test_excluding_fields(self): @autofilter(exclude_fields=("indexed_int", "indexed_char", )) class SampleApiV7(ListAPIView): permission_classes = (AllowAny,) serializer_class = SampleModelForAutofilterSerializerVer1 queryset = SampleModelForAutofilter.objects.all() self.assertEqual(set(SampleApiV7.filter_fields.keys()), {"id", "fk", "indexed_text", "indexed_url", "indexed_email", "nullable_field", "unique_text"}) def test_integration_filtering(self): response = self.client.get(reverse("autofilter_test"), data={"id__gt": 0}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 2) response = self.client.get(reverse("autofilter_test"), data={"nullable_field__isnull": True}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa2.id) self.assertIsNone(response.data[0]["nullable_field"]) response = self.client.get(reverse("autofilter_test"), data={"nullable_field__isnull": False}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa1.id) self.assertEqual(response.data[0]["nullable_field"], 1) response = self.client.get(reverse("autofilter_test"), data={"id": self.smfa1.id}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa1.id) response = self.client.get(reverse("autofilter_with_class_test"), data={"indexed_int__lt": 2}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa1.id) response = self.client.get( reverse("autofilter_with_class_test"), data={"indexed_int__lte": 2, "indexed__gt": 0} ) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 2) self.assertEqual(response.data[0]["id"], self.smfa1.id) self.assertEqual(response.data[1]["id"], self.smfa2.id) response = self.client.get( reverse("autofilter_with_class_test"), data={"indexed_int__lte": 2, "indexed_int__gt": 1} ) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa2.id) response = self.client.get(reverse("autofilter_with_class_test"), data={"indexed_text__icontains": "Orem"}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa2.id) response = self.client.get(reverse("autofilter_with_class_test"), data={"indexed_text__istartswith": "lOr"}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]["id"], self.smfa2.id) response = self.client.get(reverse("autofilter_with_class_test"), data={"indexed_text__istartswith": "lr"}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 0) def test_integration_ordering(self): response = self.client.get(reverse("autofilter_test"), data={"ordering": 'id'}) self.assertEqual(response.status_code, 200) self.assertGreater(response.data[1]["id"], response.data[0]["id"]) response = self.client.get(reverse("autofilter_test"), data={"ordering": '-id'}) self.assertEqual(response.status_code, 200) self.assertGreater(response.data[0]["id"], response.data[1]["id"]) response = self.client.get(reverse("autofilter_with_class_test"), data={"ordering": 'indexed_int'}) self.assertEqual(response.status_code, 200) self.assertGreater(response.data[1]["id"], response.data[0]["id"]) response = self.client.get(reverse("autofilter_with_class_test"), data={"ordering": '-indexed_int'}) self.assertEqual(response.status_code, 200) self.assertGreater(response.data[0]["id"], response.data[1]["id"])