diff --git a/django_filters/utils.py b/django_filters/utils.py index 781d3f436..53e29bcb4 100644 --- a/django_filters/utils.py +++ b/django_filters/utils.py @@ -317,7 +317,8 @@ def translate_validation(error_dict): from rest_framework.exceptions import ValidationError, ErrorDetail exc = OrderedDict( - (key, [ErrorDetail(e.message, code=e.code) for e in error_list]) + (key, [ErrorDetail( + e.message % (e.params or {}), code=e.code) for e in error_list]) for key, error_list in error_dict.as_data().items() ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 2d89a9a54..e944ec427 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -8,7 +8,7 @@ from django.utils.functional import Promise from django.utils.timezone import get_default_timezone -from django_filters import FilterSet +from django_filters import FilterSet, ModelMultipleChoiceFilter from django_filters.exceptions import FieldLookupError from django_filters.utils import ( MigrationNotice, @@ -511,6 +511,13 @@ class Meta: model = Article fields = ['id', 'author', 'name'] + class G(FilterSet): + author = ModelMultipleChoiceFilter(queryset=User.objects.all()) + + class Meta: + model = Article + fields = ['id', 'author', 'name'] + def test_error_detail(self): f = self.F(data={'id': 'foo', 'author': 'bar', 'name': 'baz'}) exc = translate_validation(f.errors) @@ -520,6 +527,15 @@ def test_error_detail(self): 'author': ['Select a valid choice. That choice is not one of the available choices.'], }) + f = self.G({'author': ['bar', 'baz']}) + exc = translate_validation(f.errors) + + # NOTE(stephenfin): Because we can't guarantee the order than filters + # are evaluated, we don't use 'assertDictEqual' here + self.assertEqual(set(exc.detail.keys()), {'author', }) + self.assertRegex(str(exc.detail['author'][0]), + '"ba[rz]" is not a valid value for a primary key.') + def test_full_error_details(self): f = self.F(data={'id': 'foo', 'author': 'bar', 'name': 'baz'}) exc = translate_validation(f.errors)