Merge pull request #524 from carltongibson/develop

Version 0.15.3
This commit is contained in:
Carlton Gibson 2016-10-17 09:58:55 +02:00 committed by GitHub
commit 47042b9498
11 changed files with 71 additions and 20 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.15.2 current_version = 0.15.3
commit = False commit = False
tag = False tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))? parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?

View File

@ -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) Version 0.15.2 (2016-09-29)
--------------------------- ---------------------------

View File

@ -3,7 +3,7 @@ from __future__ import absolute_import
from .filterset import FilterSet from .filterset import FilterSet
from .filters import * from .filters import *
__version__ = '0.15.2' __version__ = '0.15.3'
def parse_version(version): def parse_version(version):

View File

@ -1,4 +1,6 @@
from __future__ import absolute_import
import django import django
from django.conf import settings from django.conf import settings
@ -12,6 +14,13 @@ except ImportError:
is_crispy = 'crispy_forms' in settings.INSTALLED_APPS and crispy_forms 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): def remote_field(field):
""" """
https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes

View File

@ -89,3 +89,15 @@ class DjangoFilterBackend(BaseFilterBackend):
return template_render(template, context={ return template_render(template, context={
'filter': filter_instance '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 `<name>_0`, `<name>_1`, etc...
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 [
compat.coreapi.Field(name=field_name, required=False, location='query')
for field_name in filter_class().filters.keys()
]

View File

@ -48,9 +48,9 @@ copyright = u'2013, Alex Gaynor and others.'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.15.2' version = '0.15.3'
# The full version, including alpha/beta/rc tags. # 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 # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -12,6 +12,8 @@ Meta options
- :ref:`order_by <order-by>` - :ref:`order_by <order-by>`
- :ref:`form <form>` - :ref:`form <form>`
- :ref:`together <together>` - :ref:`together <together>`
- filter_overrides
- :ref:`strict <strict>`
.. _model: .. _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 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 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: .. _form:
@ -152,18 +154,6 @@ field set must either be all or none present in the request for
fields = ['price', 'release_date', 'rating'] fields = ['price', 'release_date', 'rating']
together = ['rating', 'price'] 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: .. _strict:
``strict`` ``strict``

View File

@ -1,3 +1,5 @@
coreapi
coverage coverage
mock mock
pytz pytz

View File

@ -1,3 +1,3 @@
-r travis-ci.txt -r test-ci.txt
django django
djangorestframework djangorestframework

View File

@ -6,7 +6,7 @@ f = open('README.rst')
readme = f.read() readme = f.read()
f.close() f.close()
version = '0.15.2' version = '0.15.3'
if sys.argv[-1] == 'publish': if sys.argv[-1] == 'publish':
if os.system("pip freeze | grep wheel"): if os.system("pip freeze | grep wheel"):

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import datetime import datetime
from decimal import Decimal from decimal import Decimal
from unittest import skipIf
from django.conf.urls import url from django.conf.urls import url
from django.test import TestCase from django.test import TestCase
@ -17,7 +18,7 @@ except ImportError:
from rest_framework import generics, serializers, status from rest_framework import generics, serializers, status
from rest_framework.test import APIRequestFactory 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 DjangoFilterBackend, FilterSet
from django_filters.rest_framework import backends from django_filters.rest_framework import backends
@ -121,6 +122,35 @@ urlpatterns = [
] ]
@skipIf(compat.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): class CommonFilteringTestCase(TestCase):
def _serialize_object(self, obj): def _serialize_object(self, obj):
return {'id': obj.id, 'text': obj.text, 'decimal': str(obj.decimal), 'date': obj.date.isoformat()} return {'id': obj.id, 'text': obj.text, 'decimal': str(obj.decimal), 'date': obj.date.isoformat()}