Simple enough example - I have a bit of Django code that starts with a queryset...
queryset = MyModel.objects.all()
Later on it performs various filtering, depending on some configurable options...
if something:
queryset = self.queryset.filter(foo=some_foo)
if another_thing:
queryset = self.queryset.filter(bar=some_bar)
And finally it performs the lookup...
try:
obj = queryset.get()
except ObjectDoesNotExist:
raise ValidationError('Does not exist')
Now, because of the flexible way that the filtering needs to occur, it's possible that the some_foo
or some_bar
variables might not be of the correct type (eg. we could end up with an empty string attempting to filter against an integer field.) so it's possible for this code to end up raising a TypeError
or a ValueError
.
That's fine, and I can handle the case appropriately, but what's not clear to me from the ORM contract, is at what point should I expect those exceptions to be raised.
.filter()
statement?....get()
statement?...To answer the original question, a FieldError
and ValueError
are raised on the call to filter, when a new queryset is built:
>>> a = Account.objects.all()
>>> a = a.filter(id=3)
>>> a = a.filter(no_exist=3)
<snip>
FieldError: Cannot resolve keyword 'no_exist' into field. Choices are: active, created_on, group, id, ...
>>> a = Account.objects.all()
>>> a = a.filter(id='abc')
ValueError: invalid literal for int() with base 10: 'abc'
I'll also add that this pattern seems misleading to me, in that filter
is normally used to return a list/iterable of models, rather than one as with get
. For clarity and easier handling of the exceptions, I'd suggest this pattern:
kwargs = {}
if something:
kwargs['foo'] = some_foo
if another_thing:
kwargs['bar'] = some_bar
# handle if kwargs is empty
try:
obj = MyModel.objects.get(**kwargs)
except (FieldError, ValueError, ObjectDoesNotExist):
raise ValidationError('Does not exist')
The other added benefit is that, IIRC, the work of cloning querysets is relatively expensive, so you ignore that overhead, while at the same time making the code cleaner. Going back to your question, with this pattern there's no question where the exception will be raised.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With