Skip to content

Commit cb13d69

Browse files
committed
closes #6
1 parent df8ce7b commit cb13d69

File tree

3 files changed

+32
-13
lines changed

3 files changed

+32
-13
lines changed

django_enum/filters.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from django_enum.forms import EnumChoiceField
88

99
try:
10-
from django_filters import ChoiceFilter, Filter, filterset
10+
from django_filters import Filter, TypedChoiceFilter, filterset
1111

12-
class EnumFilter(ChoiceFilter):
12+
class EnumFilter(TypedChoiceFilter):
1313
"""
1414
Use this filter class instead of ``ChoiceFilter`` to get filters to
1515
accept Enum labels and symmetric properties.
@@ -30,18 +30,24 @@ class Color(TextChoices, s('rgb'), s('hex', case_fold=True)):
3030
values: ?color=R, ?color=G, ?color=B. ``EnumFilter`` will accept query
3131
parameter values from any of the symmetric properties: ?color=Red,
3232
?color=ff0000, etc...
33+
34+
:param enum: The class of the enumeration containing the values to
35+
filter on
36+
:param strict: If False (default), values not in the enumeration will
37+
be searchable.
38+
:param kwargs: Any additional arguments for base classes
3339
"""
3440
field_class: FormField = EnumChoiceField
3541

36-
def __init__(self, *, enum, **kwargs):
42+
def __init__(self, *, enum, strict=False, **kwargs):
3743
self.enum = enum
3844
super().__init__(
3945
enum=enum,
4046
choices=kwargs.pop('choices', self.enum.choices),
47+
strict=strict,
4148
**kwargs
4249
)
4350

44-
4551
class FilterSet(filterset.FilterSet):
4652
"""
4753
Use this class instead of django-filter's ``FilterSet`` class to
@@ -56,7 +62,10 @@ def filter_for_lookup(
5662
) -> Tuple[Type[Filter], dict]:
5763
"""For EnumFields use the EnumFilter class by default"""
5864
if hasattr(field, 'enum') and hasattr(field.enum, 'choices'):
59-
return EnumFilter, {'enum': field.enum}
65+
return EnumFilter, {
66+
'enum': field.enum,
67+
'strict': getattr(field, 'strict', False)
68+
}
6069
return super().filter_for_lookup(field, lookup_type)
6170

6271

django_enum/forms.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class EnumChoiceField(TypedChoiceField):
5353
enumeration value. This value will be returned when any "empty" value
5454
is encountered. If unspecified the default empty value of '' is
5555
returned.
56+
:param empty_values: Override the list of what are considered to be empty
57+
values.
5658
:param strict: If False, values not included in the enumeration list, but
5759
of the same primitive type are acceptable.
5860
:param choices: Override choices, otherwise enumeration choices attribute
@@ -114,14 +116,15 @@ def __init__(
114116
*,
115117
empty_value: Any = _Unspecified,
116118
strict: bool = strict_,
119+
empty_values: List[Any] = TypedChoiceField.empty_values,
117120
choices: Iterable[Tuple[Any, str]] = (),
118121
**kwargs
119122
):
120123
self.strict = strict
121124
if not self.strict:
122125
kwargs.setdefault('widget', NonStrictSelect)
123126

124-
self.empty_values = kwargs.pop('empty_values', self.empty_values)
127+
self.empty_values = empty_values
125128

126129
super().__init__(
127130
choices=choices or getattr(self.enum, 'choices', choices),

django_enum/tests/tests.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ def test_field_validation(self):
952952
]:
953953
try:
954954
enum_field.clean(bad_value)
955-
except ValidationError:
955+
except ValidationError: # pragma: no cover
956956
self.fail(f'non-strict choice field for {enum_field.enum} raised ValidationError on {bad_value} during clean')
957957

958958
def test_non_strict_field(self):
@@ -1303,7 +1303,7 @@ def get_enum_val(self, enum, value, null=True, coerce=True, strict=True):
13031303
return enum(float(value))
13041304
return enum(value)
13051305
except ValueError as err:
1306-
if strict:
1306+
if strict: # pragma: no cover
13071307
raise err
13081308

13091309
if value not in {None, ''}:
@@ -1367,7 +1367,7 @@ def verify_form(self, obj, soup):
13671367
coerce=field.coerce,
13681368
strict=field.strict
13691369
)
1370-
except ValueError:
1370+
except ValueError: # pragma: no cover
13711371
self.assertFalse(field.strict)
13721372
value = self.enum_primitive(field.name)(option['value'])
13731373
self.assertEqual(str(expected[value]), option.text)
@@ -1393,8 +1393,8 @@ def verify_form(self, obj, soup):
13931393
self.assertFalse(
13941394
null_opt,
13951395
f"An unexpected null option is present on {field.name}"
1396-
) # pragma: no cover
1397-
elif field.blank:
1396+
)
1397+
elif field.blank: # pragma: no cover
13981398
self.assertTrue(
13991399
null_opt,
14001400
f"Expected a null option on field {field.name}, but none was present."
@@ -1489,14 +1489,20 @@ def test_django_filter(self):
14891489
reverse(f'{self.NAMESPACE}:enum-filter')
14901490
)
14911491

1492-
def do_test_django_filter(self, url):
1492+
def do_test_django_filter(self, url, skip_non_strict=True):
14931493
"""
14941494
Exhaustively test query parameter permutations based on data
14951495
created in setUp
14961496
"""
14971497
client = Client()
14981498
for attr, val_map in self.values.items():
14991499
for val, objs in val_map.items():
1500+
if (
1501+
skip_non_strict and not
1502+
self.MODEL_CLASS._meta.get_field(attr).strict and not
1503+
any([val == en for en in self.MODEL_CLASS._meta.get_field(attr).enum])
1504+
):
1505+
continue
15001506
if val in {None, ''}:
15011507
# todo how to query None or empty?
15021508
continue
@@ -2180,7 +2186,8 @@ def field_filter_properties(self):
21802186
if DJANGO_FILTERS_INSTALLED:
21812187
def test_django_filter(self):
21822188
self.do_test_django_filter(
2183-
reverse(f'{self.NAMESPACE}:enum-filter-symmetric')
2189+
reverse(f'{self.NAMESPACE}:enum-filter-symmetric'),
2190+
skip_non_strict=False
21842191
)
21852192
else:
21862193
pass # pragma: no cover

0 commit comments

Comments
 (0)