Add more explanatory FieldLookupError

This commit is contained in:
Ryan P Kilby 2016-04-16 20:39:35 -04:00
parent bd25121332
commit f61d7a7324
4 changed files with 58 additions and 22 deletions

View File

@ -0,0 +1,9 @@
from django.core.exceptions import FieldError
class FieldLookupError(FieldError):
def __init__(self, model_field, lookup_expr):
super(FieldLookupError, self).__init__(
"Unsupported lookup '%s' for field '%s'." % (lookup_expr, model_field)
)

View File

@ -1,12 +1,14 @@
from django.conf import settings
from django.core.exceptions import FieldError
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.expressions import Expression
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel
from django.utils import timezone
from django.utils import six, timezone
from .compat import remote_model
from .exceptions import FieldLookupError
def try_dbfield(fn, field_class):
@ -78,22 +80,25 @@ def resolve_field(model_field, lookup_expr):
assert len(lookups) > 0
while lookups:
name = lookups[0]
# If there is just one part left, try first get_lookup() so
# that if the lhs supports both transform and lookup for the
# name, then lookup will be picked.
if len(lookups) == 1:
final_lookup = lhs.get_lookup(name)
if not final_lookup:
# We didn't find a lookup. We are going to interpret
# the name as transform, and do an Exact lookup against
# it.
lhs = query.try_transform(lhs, name, lookups)
final_lookup = lhs.get_lookup('exact')
return lhs.output_field, final_lookup.lookup_name
lhs = query.try_transform(lhs, name, lookups)
lookups = lookups[1:]
try:
while lookups:
name = lookups[0]
# If there is just one part left, try first get_lookup() so
# that if the lhs supports both transform and lookup for the
# name, then lookup will be picked.
if len(lookups) == 1:
final_lookup = lhs.get_lookup(name)
if not final_lookup:
# We didn't find a lookup. We are going to interpret
# the name as transform, and do an Exact lookup against
# it.
lhs = query.try_transform(lhs, name, lookups)
final_lookup = lhs.get_lookup('exact')
return lhs.output_field, final_lookup.lookup_name
lhs = query.try_transform(lhs, name, lookups)
lookups = lookups[1:]
except FieldError as e:
six.raise_from(FieldLookupError(model_field, lookup_expr), e)
def handle_timezone(value):

View File

@ -28,6 +28,7 @@ from django_filters.filters import NumberFilter
from django_filters.filters import RangeFilter
from django_filters.filters import TimeRangeFilter
# from django_filters.widgets import LinkWidget
from django_filters.exceptions import FieldLookupError
from .models import User
from .models import Comment
@ -1718,3 +1719,16 @@ class MiscFilterSetTests(TestCase):
f = F({'status': '2'}, queryset=qs)
self.assertEqual(len(f.qs), 2)
self.assertEqual(f.count(), 2)
def test_invalid_field_lookup(self):
# We want to ensure that non existent lookups (or just simple misspellings)
# throw a useful exception containg the field and lookup expr.
with self.assertRaises(FieldLookupError) as context:
class F(FilterSet):
class Meta:
model = User
fields = {'username': ['flub']}
exc = str(context.exception)
self.assertIn('tests.User.username', exc)
self.assertIn('flub', exc)

View File

@ -5,9 +5,9 @@ import django
from django.test import TestCase
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.core.exceptions import FieldError
from django_filters.utils import get_model_field, resolve_field
from django_filters.exceptions import FieldLookupError
from .models import User
from .models import Article
@ -156,11 +156,19 @@ class ResolveFieldTests(TestCase):
def test_invalid_lookup_expression(self):
model_field = Article._meta.get_field('published')
with self.assertRaises(FieldError):
field, lookup = resolve_field(model_field, 'invalid_lookup')
with self.assertRaises(FieldLookupError) as context:
resolve_field(model_field, 'invalid_lookup')
exc = str(context.exception)
self.assertIn(str(model_field), exc)
self.assertIn('invalid_lookup', exc)
def test_invalid_transformed_lookup_expression(self):
model_field = Article._meta.get_field('published')
with self.assertRaises(FieldError):
field, lookup = resolve_field(model_field, 'date__invalid_lookup')
with self.assertRaises(FieldLookupError) as context:
resolve_field(model_field, 'date__invalid_lookup')
exc = str(context.exception)
self.assertIn(str(model_field), exc)
self.assertIn('date__invalid_lookup', exc)