Add strictness setting
This commit is contained in:
parent
f8a0d1a9cf
commit
67f7edfa23
|
@ -1,5 +1,6 @@
|
|||
# flake8: noqa
|
||||
from __future__ import absolute_import
|
||||
from .constants import STRICTNESS
|
||||
from .filterset import FilterSet
|
||||
from .filters import *
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ from django.conf import settings as dj_settings
|
|||
from django.core.signals import setting_changed
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .constants import STRICTNESS
|
||||
from .utils import deprecate
|
||||
|
||||
|
||||
|
@ -16,6 +17,8 @@ DEFAULTS = {
|
|||
'NULL_CHOICE_LABEL': None,
|
||||
'NULL_CHOICE_VALUE': 'null',
|
||||
|
||||
'STRICTNESS': STRICTNESS.RETURN_NO_RESULTS,
|
||||
|
||||
'VERBOSE_LOOKUPS': {
|
||||
# transforms don't need to be verbose, since their expressions are chained
|
||||
'date': _('date'),
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
ALL_FIELDS = '__all__'
|
||||
|
||||
|
||||
class STRICTNESS:
|
||||
class IGNORE:
|
||||
pass
|
||||
|
||||
class RETURN_NO_RESULTS:
|
||||
pass
|
||||
|
||||
class RAISE_VALIDATION_ERROR:
|
||||
pass
|
||||
|
||||
# Values of False & True chosen for backward compatability reasons.
|
||||
# Originally, these were the only options.
|
||||
_LEGACY = {
|
||||
False: IGNORE,
|
||||
True: RETURN_NO_RESULTS,
|
||||
"RAISE": RAISE_VALIDATION_ERROR,
|
||||
}
|
|
@ -10,10 +10,11 @@ from django.db import models
|
|||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.fields.related import ForeignObjectRel
|
||||
from django.utils import six
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .conf import settings
|
||||
from .compat import remote_field, remote_queryset
|
||||
from .constants import ALL_FIELDS, STRICTNESS
|
||||
from .filters import (Filter, CharFilter, BooleanFilter, BaseInFilter, BaseRangeFilter,
|
||||
ChoiceFilter, DateFilter, DateTimeFilter, TimeFilter, ModelChoiceFilter,
|
||||
ModelMultipleChoiceFilter, NumberFilter, UUIDFilter,
|
||||
|
@ -24,16 +25,6 @@ from .utils import try_dbfield, get_all_model_fields, get_model_field, resolve_f
|
|||
ORDER_BY_FIELD = 'o'
|
||||
|
||||
|
||||
class STRICTNESS(object):
|
||||
"""
|
||||
Values of False & True chosen for backward compatability reasons.
|
||||
Originally, these were the only options.
|
||||
"""
|
||||
IGNORE = False
|
||||
RETURN_NO_RESULTS = True
|
||||
RAISE_VALIDATION_ERROR = "RAISE"
|
||||
|
||||
|
||||
def get_declared_filters(bases, attrs, with_base_filters=True):
|
||||
filters = []
|
||||
for filter_name, obj in list(attrs.items()):
|
||||
|
@ -62,10 +53,10 @@ def filters_for_model(model, fields=None, exclude=None, filter_for_field=None,
|
|||
|
||||
# Setting exclude with no fields implies all other fields.
|
||||
if exclude is not None and fields is None:
|
||||
fields = '__all__'
|
||||
fields = ALL_FIELDS
|
||||
|
||||
# All implies all db fields associated with a filter_class.
|
||||
if fields == '__all__':
|
||||
if fields == ALL_FIELDS:
|
||||
fields = get_all_model_fields(model)
|
||||
|
||||
# Loop through the list of fields.
|
||||
|
@ -160,7 +151,7 @@ class FilterSetOptions(object):
|
|||
self.order_by = getattr(options, 'order_by', False)
|
||||
self.order_by_field = getattr(options, 'order_by_field', ORDER_BY_FIELD)
|
||||
|
||||
self.strict = getattr(options, 'strict', STRICTNESS.RETURN_NO_RESULTS)
|
||||
self.strict = getattr(options, 'strict', None)
|
||||
|
||||
self.form = getattr(options, 'form', forms.Form)
|
||||
|
||||
|
@ -286,7 +277,14 @@ class BaseFilterSet(object):
|
|||
self.form_prefix = prefix
|
||||
|
||||
# What to do on on validation errors
|
||||
self.strict = self._meta.strict if strict is None else strict
|
||||
# Fallback to meta, then settings strictness
|
||||
if strict is None:
|
||||
strict = self._meta.strict
|
||||
if strict is None:
|
||||
strict = settings.STRICTNESS
|
||||
|
||||
# transform legacy values
|
||||
self.strict = STRICTNESS._LEGACY.get(strict, strict)
|
||||
|
||||
self.request = request
|
||||
|
||||
|
@ -326,7 +324,7 @@ class BaseFilterSet(object):
|
|||
if not self.form.is_valid():
|
||||
if self.strict == STRICTNESS.RAISE_VALIDATION_ERROR:
|
||||
raise forms.ValidationError(self.form.errors)
|
||||
elif bool(self.strict) == STRICTNESS.RETURN_NO_RESULTS:
|
||||
elif self.strict == STRICTNESS.RETURN_NO_RESULTS:
|
||||
self._qs = self.queryset.none()
|
||||
return self._qs
|
||||
# else STRICTNESS.IGNORE... ignoring
|
||||
|
@ -527,7 +525,7 @@ class FilterSet(six.with_metaclass(FilterSetMetaclass, BaseFilterSet)):
|
|||
|
||||
|
||||
def filterset_factory(model):
|
||||
meta = type(str('Meta'), (object,), {'model': model, 'fields': '__all__'})
|
||||
meta = type(str('Meta'), (object,), {'model': model, 'fields': ALL_FIELDS})
|
||||
filterset = type(str('%sFilterSet' % model._meta.object_name),
|
||||
(FilterSet,), {'Meta': meta})
|
||||
return filterset
|
||||
|
|
|
@ -89,3 +89,11 @@ For example, you could add verbose output for "exact" lookups.
|
|||
'exact': 'is equal to',
|
||||
})
|
||||
return verbose_lookups
|
||||
|
||||
|
||||
FILTERS_STRICTNESS
|
||||
------------------
|
||||
|
||||
DEFAULT: ``STRICTNESS.RETURN_NO_RESULTS``
|
||||
|
||||
Set the global default for FilterSet :ref:`strictness <strict>`.
|
||||
|
|
|
@ -2,17 +2,23 @@
|
|||
from django.test import TestCase, override_settings
|
||||
|
||||
from django_filters.conf import settings
|
||||
from django_filters import FilterSet, STRICTNESS
|
||||
|
||||
from tests.models import User
|
||||
|
||||
|
||||
class DefaultSettingsTests(TestCase):
|
||||
|
||||
def test_verbose_loookups(self):
|
||||
def test_verbose_lookups(self):
|
||||
self.assertIsInstance(settings.VERBOSE_LOOKUPS, dict)
|
||||
self.assertIn('exact', settings.VERBOSE_LOOKUPS)
|
||||
|
||||
def test_disable_help_text(self):
|
||||
self.assertFalse(settings.DISABLE_HELP_TEXT)
|
||||
|
||||
def test_strictness(self):
|
||||
self.assertEqual(settings.STRICTNESS, STRICTNESS.RETURN_NO_RESULTS)
|
||||
|
||||
def test_help_text_filter(self):
|
||||
self.assertTrue(settings.HELP_TEXT_FILTER)
|
||||
|
||||
|
@ -29,6 +35,44 @@ class DefaultSettingsTests(TestCase):
|
|||
self.assertEqual(settings.NULL_CHOICE_VALUE, 'null')
|
||||
|
||||
|
||||
class StrictnessTests(TestCase):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
def test_settings_default(self):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.RETURN_NO_RESULTS)
|
||||
|
||||
def test_ignore(self):
|
||||
with override_settings(FILTERS_STRICTNESS=STRICTNESS.IGNORE):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.IGNORE)
|
||||
|
||||
def test_return_no_results(self):
|
||||
with override_settings(FILTERS_STRICTNESS=STRICTNESS.RETURN_NO_RESULTS):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.RETURN_NO_RESULTS)
|
||||
|
||||
def test_raise_validation_error(self):
|
||||
with override_settings(FILTERS_STRICTNESS=STRICTNESS.RAISE_VALIDATION_ERROR):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.RAISE_VALIDATION_ERROR)
|
||||
|
||||
def test_legacy_ignore(self):
|
||||
with override_settings(FILTERS_STRICTNESS=False):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.IGNORE)
|
||||
|
||||
def test_legacy_return_no_results(self):
|
||||
with override_settings(FILTERS_STRICTNESS=True):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.RETURN_NO_RESULTS)
|
||||
|
||||
def test_legacy_raise_validation_error(self):
|
||||
with override_settings(FILTERS_STRICTNESS='RAISE'):
|
||||
self.assertEqual(self.F().strict, STRICTNESS.RAISE_VALIDATION_ERROR)
|
||||
|
||||
def test_legacy_differentiation(self):
|
||||
self.assertNotEqual(STRICTNESS.IGNORE, False)
|
||||
self.assertNotEqual(STRICTNESS.RETURN_NO_RESULTS, True)
|
||||
self.assertNotEqual(STRICTNESS.RAISE_VALIDATION_ERROR, 'RAISE')
|
||||
|
||||
|
||||
class OverrideSettingsTests(TestCase):
|
||||
|
||||
def test_attribute_override(self):
|
||||
|
|
|
@ -453,7 +453,6 @@ class DeprecatedOrderingFilterSetTests(TestCase):
|
|||
order_by = ['status']
|
||||
strict = STRICTNESS.IGNORE
|
||||
|
||||
self.assertFalse(F._meta.strict)
|
||||
f = F({'o': 'username'}, queryset=self.qs)
|
||||
self.assertQuerysetEqual(
|
||||
f.qs, ['alex', 'jacob', 'aaron', 'carl'], lambda o: o.username)
|
||||
|
|
|
@ -5,8 +5,9 @@ import unittest
|
|||
|
||||
import django
|
||||
from django.db import models
|
||||
from django.test import TestCase
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from django_filters.constants import STRICTNESS
|
||||
from django_filters.filterset import FilterSet
|
||||
from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS
|
||||
from django_filters.filters import Filter
|
||||
|
@ -573,6 +574,45 @@ class FilterSetInstantiationTests(TestCase):
|
|||
self.assertEqual(f.request, m)
|
||||
|
||||
|
||||
class FilterSetStrictnessTests(TestCase):
|
||||
|
||||
def test_settings_default(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
# Ensure default is not IGNORE
|
||||
self.assertEqual(F().strict, STRICTNESS.RETURN_NO_RESULTS)
|
||||
|
||||
# override and test
|
||||
with override_settings(FILTERS_STRICTNESS=STRICTNESS.IGNORE):
|
||||
self.assertEqual(F().strict, STRICTNESS.IGNORE)
|
||||
|
||||
def test_meta_value(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
strict = STRICTNESS.IGNORE
|
||||
|
||||
self.assertEqual(F().strict, STRICTNESS.IGNORE)
|
||||
|
||||
def test_init_default(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
strict = STRICTNESS.IGNORE
|
||||
|
||||
strict = STRICTNESS.RAISE_VALIDATION_ERROR
|
||||
self.assertEqual(F(strict=strict).strict, strict)
|
||||
|
||||
def test_legacy_value(self):
|
||||
class F(FilterSet):
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
self.assertEqual(F(strict=False).strict, STRICTNESS.IGNORE)
|
||||
|
||||
|
||||
class FilterSetTogetherTests(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue