Closed rvdrijst closed 3 years ago
This is unfortunately not possible to fix without causing other issues, and cutting against the grain of Django's intent. The logic for this is buried deep in RelatedLookupMixin which is used by the ForeignKey field. It calls get_prep_lookup()
on the field to validate the value. It has this comment:
# We need to run the related field's get_prep_value(). Consider case
# ForeignKey to IntegerField given value 'abc'. The ForeignKey itself
# doesn't have validation for non-integers, so we must run validation
# using the target field.
Your solution is a possible one to workaround this particular problem, but like I said, I'm worried about it being too "magic" and/or causing issues elsewhere. The current behavior mimics that of other built-in fields. If you try to do a filter on a ForeignKey field that points to an AutoField or IntegerField with an invalid int, such as a string, it will throw a ValueError as well.
This is related to the closed issue #17 that deals only with direct lookups.
I have the default
HASHID_FIELD_LOOKUP_EXCEPTION = False
, which works for as expected if I look up an object by primary key directly.However, if I try to filter a queryset by hashid to a related field (e.g. a foreign key) the queryset throws a ValueError if the hashid is not valid. I understand why, but for my purposes it shouldn't really matter whether I pass in a valid but non-existent key, or an invalid (and equally non-existent) key.
Example:
Because it's quite tricky to catch invalid hashids before they are passed into the queryset (a simple regex is clearly not enough and in my case the salt is different for each model) this leads to having to handle two cases: empty results and
ValueError
s. Especially inside Django Rest Frameworks internals (like filters) this is quite cumbersome, and actually I don't care whether the hashid is invalid or just doesn't exist, as long as it matches basic sanity checks with a regex.So, my solution (a bit hacky so I'm sure there is a cleaner solution, but this seems to work at least on Postgres):
Also this makes sure that invalid hashids don't trigger a different error than non-existent hashids, which might expose some information on how the hashids are built up.