Opened 12 years ago
Last modified 12 years ago
#19616 closed Bug
QuerySet.__contains__ tries to check the length of a None — at Version 3
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.4 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | yes | UI/UX: | no |
Description (last modified by )
This is the code from QuerySet (version 1.42).
As you can see by the lines I've bolded, although _result_cache might be None, it is still being checked for len()
def __contains__(self, val): # The 'in' operator works without this method, due to __iter__. This # implementation exists only to shortcut the creation of Model # instances, by bailing out early if we find a matching element. pos = 0 if self._result_cache is not None: if val in self._result_cache: return True elif self._iter is None: # iterator is exhausted, so we have our answer return False # remember not to check these again: pos = len(self._result_cache) else: # We need to start filling the result cache out. The following # ensures that self._iter is not None and self._result_cache is not # None it = iter(self) # Carry on, one result at a time. while True: if len(self._result_cache) <= pos: self._fill_cache(num=1)
Change History (3)
follow-up: 2 comment:1 by , 12 years ago
comment:2 by , 12 years ago
Replying to Alex:
Can you actually reproduce this in any way? Calling
iter(self)
should cause_result_cache
to start being a list.
Yes, I noticed this because it happened to me.
The reproduction is a bit complex, though.
I used this snippet:
http://djangosnippets.org/snippets/1034/
And it happened when trying to iterate an empty QuerySet.
I naturally thought that this is a bug with me or the snippet, but looking at the code it is pretty obvious that although the function expects that _result_cache might be None it still tries to len() it.
comment:3 by , 12 years ago
Description: | modified (diff) |
---|
Looking at the code and the comments in the else
branch, it actually seems very obvious that the function has covered it's bases about whether self._result_cache is None
or not. We need either some further analysis as to why it is wrong, or a simple test case that ought to work.
Can you actually reproduce this in any way? Calling
iter(self)
should cause_result_cache
to start being a list.