From 3f2df252e20aceff2104ef81a65c214d89e1399a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 7 Oct 2016 21:16:47 +0200 Subject: [PATCH 1/5] Fix docs with regard to moving Non-Meta options --- docs/ref/filterset.txt | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/docs/ref/filterset.txt b/docs/ref/filterset.txt index b934327..a4d851b 100644 --- a/docs/ref/filterset.txt +++ b/docs/ref/filterset.txt @@ -12,6 +12,8 @@ Meta options - :ref:`order_by ` - :ref:`form
` - :ref:`together ` +- filter_overrides +- :ref:`strict ` .. _model: @@ -120,7 +122,7 @@ This lets you override the displayed names for your ordering fields:: Note that the default query parameter name used for ordering is ``o``. You can override this by setting an ``order_by_field`` attribute on the -``FilterSet`` class to the string value you would like to use. +``FilterSet``'s Meta class to the string value you would like to use. .. _form: @@ -152,18 +154,6 @@ field set must either be all or none present in the request for fields = ['price', 'release_date', 'rating'] together = ['rating', 'price'] - -Non-Meta options ----------------- - -Note that these options do not go in the Meta class, they are specified directly -in your FilterSet class. - -- filter_overrides -- order_by_field -- :ref:`strict ` - - .. _strict: ``strict`` From 982c5ff1a67ffe3c028d24a67f9152e61edf61f5 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Wed, 21 Sep 2016 17:43:07 -0400 Subject: [PATCH 2/5] Port get_schema_fields from DRF --- django_filters/rest_framework/backends.py | 14 +++++++++- tests/rest_framework/test_backends.py | 31 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/django_filters/rest_framework/backends.py b/django_filters/rest_framework/backends.py index 4027ac2..eefc5fe 100644 --- a/django_filters/rest_framework/backends.py +++ b/django_filters/rest_framework/backends.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.template import Template, TemplateDoesNotExist, loader -from rest_framework.compat import template_render +from rest_framework.compat import coreapi, template_render from rest_framework.filters import BaseFilterBackend from .. import compat @@ -89,3 +89,15 @@ class DjangoFilterBackend(BaseFilterBackend): return template_render(template, context={ 'filter': filter_instance }) + + def get_schema_fields(self, view): + # This is not compatible with widgets where the query param differs from the + # filter's attribute name. Notably, this includes `MultiWidget`, where query + # params will be of the format `_0`, `_1`, etc... + assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + filter_class = self.get_filter_class(view, view.get_queryset()) + + return [] if not filter_class else [ + coreapi.Field(name=field_name, required=False, location='query') + for field_name in filter_class().filters.keys() + ] diff --git a/tests/rest_framework/test_backends.py b/tests/rest_framework/test_backends.py index f6b383c..496eecd 100644 --- a/tests/rest_framework/test_backends.py +++ b/tests/rest_framework/test_backends.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import datetime from decimal import Decimal +from unittest import skipIf from django.conf.urls import url from django.test import TestCase @@ -15,6 +16,7 @@ except ImportError: from django.core.urlresolvers import reverse from rest_framework import generics, serializers, status +from rest_framework.compat import coreapi from rest_framework.test import APIRequestFactory from django_filters import filters @@ -121,6 +123,35 @@ urlpatterns = [ ] +@skipIf(coreapi is None, 'coreapi must be installed') +class GetSchemaFieldsTests(TestCase): + 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 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_fields_with_filter_class(self): + backend = DjangoFilterBackend() + fields = backend.get_schema_fields(FilterClassRootView()) + fields = [f.name for f in fields] + + self.assertEqual(fields, ['text', 'decimal', 'date']) + + class CommonFilteringTestCase(TestCase): def _serialize_object(self, obj): return {'id': obj.id, 'text': obj.text, 'decimal': str(obj.decimal), 'date': obj.date.isoformat()} From 0b1ec0507ba43fb391d0225efc8c8836e0702a4d Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Sun, 16 Oct 2016 19:06:46 -0400 Subject: [PATCH 3/5] Add coreapi to ci, fix test reqs --- requirements/test-ci.txt | 2 ++ requirements/test.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements/test-ci.txt b/requirements/test-ci.txt index 85ceb08..2c79c1d 100644 --- a/requirements/test-ci.txt +++ b/requirements/test-ci.txt @@ -1,3 +1,5 @@ +coreapi + coverage mock pytz diff --git a/requirements/test.txt b/requirements/test.txt index 5b885fa..b811569 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,3 +1,3 @@ --r travis-ci.txt +-r test-ci.txt django djangorestframework From bc359782fdc298044d9da0af0081b53c70ee7a2c Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Sun, 16 Oct 2016 19:13:12 -0400 Subject: [PATCH 4/5] Add coreapi/DRF compatibility --- django_filters/compat.py | 9 +++++++++ django_filters/rest_framework/backends.py | 6 +++--- tests/rest_framework/test_backends.py | 5 ++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/django_filters/compat.py b/django_filters/compat.py index e7fa88b..cbac451 100644 --- a/django_filters/compat.py +++ b/django_filters/compat.py @@ -1,4 +1,6 @@ +from __future__ import absolute_import + import django from django.conf import settings @@ -12,6 +14,13 @@ except ImportError: is_crispy = 'crispy_forms' in settings.INSTALLED_APPS and crispy_forms +# coreapi only compatible with DRF 3.4+ +try: + from rest_framework.compat import coreapi +except ImportError: + coreapi = None + + def remote_field(field): """ https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes diff --git a/django_filters/rest_framework/backends.py b/django_filters/rest_framework/backends.py index eefc5fe..37c7dfa 100644 --- a/django_filters/rest_framework/backends.py +++ b/django_filters/rest_framework/backends.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from django.template import Template, TemplateDoesNotExist, loader -from rest_framework.compat import coreapi, template_render +from rest_framework.compat import template_render from rest_framework.filters import BaseFilterBackend from .. import compat @@ -94,10 +94,10 @@ class DjangoFilterBackend(BaseFilterBackend): # This is not compatible with widgets where the query param differs from the # filter's attribute name. Notably, this includes `MultiWidget`, where query # params will be of the format `_0`, `_1`, etc... - assert coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' + assert compat.coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`' filter_class = self.get_filter_class(view, view.get_queryset()) return [] if not filter_class else [ - coreapi.Field(name=field_name, required=False, location='query') + compat.coreapi.Field(name=field_name, required=False, location='query') for field_name in filter_class().filters.keys() ] diff --git a/tests/rest_framework/test_backends.py b/tests/rest_framework/test_backends.py index 496eecd..763d093 100644 --- a/tests/rest_framework/test_backends.py +++ b/tests/rest_framework/test_backends.py @@ -16,10 +16,9 @@ except ImportError: from django.core.urlresolvers import reverse from rest_framework import generics, serializers, status -from rest_framework.compat import coreapi from rest_framework.test import APIRequestFactory -from django_filters import filters +from django_filters import compat, filters from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import backends @@ -123,7 +122,7 @@ urlpatterns = [ ] -@skipIf(coreapi is None, 'coreapi must be installed') +@skipIf(compat.coreapi is None, 'coreapi must be installed') class GetSchemaFieldsTests(TestCase): def test_fields_with_filter_fields_list(self): backend = DjangoFilterBackend() From eb298ee2a6256b57bc049f696ac7fc734c39cdee Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Mon, 17 Oct 2016 09:45:46 +0200 Subject: [PATCH 5/5] Update Changes and Version Number for 0.15.3 release --- .bumpversion.cfg | 2 +- CHANGES.rst | 8 ++++++++ django_filters/__init__.py | 2 +- docs/conf.py | 4 ++-- setup.py | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index c8432a9..3e15829 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.15.2 +current_version = 0.15.3 commit = False tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? diff --git a/CHANGES.rst b/CHANGES.rst index a474a67..2e50925 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,11 @@ +Version 0.15.3 (2016-10-17) +--------------------------- + +Adds compatibility for DRF (3.5+) get_schema_fields filter backend +introspection. + +* #492 Port get_schema_fields from DRF + Version 0.15.2 (2016-09-29) --------------------------- diff --git a/django_filters/__init__.py b/django_filters/__init__.py index cb72924..514ef04 100644 --- a/django_filters/__init__.py +++ b/django_filters/__init__.py @@ -3,7 +3,7 @@ from __future__ import absolute_import from .filterset import FilterSet from .filters import * -__version__ = '0.15.2' +__version__ = '0.15.3' def parse_version(version): diff --git a/docs/conf.py b/docs/conf.py index 752c549..befb110 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2013, Alex Gaynor and others.' # built documents. # # The short X.Y version. -version = '0.15.2' +version = '0.15.3' # The full version, including alpha/beta/rc tags. -release = '0.15.2' +release = '0.15.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 2ee6683..457d132 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ f = open('README.rst') readme = f.read() f.close() -version = '0.15.2' +version = '0.15.3' if sys.argv[-1] == 'publish': if os.system("pip freeze | grep wheel"):