#12615: Broken queryset indexing with postgresql_psycopg2 with custom through model
------------------------------------+-------------------------------------- -
Reporter: yxven | Owner: nobody
Status: closed | Milestone:
Component: Uncategorized | Version: 1.1-beta-1
Resolution: invalid | Keywords:
Stage: Unreviewed | Has_patch: 0
Needs_docs: 0 | Needs_tests: 0
Needs_better_patch: 0 |
------------------------------------+-------------------------------------- -
Changes (by russellm):
* status: new => closed
* needs_better_patch: => 0
* resolution: => invalid
* needs_tests: => 0
* needs_docs: => 0
Comment:
Although confusing, this actually isn't an error on Django's part. Your
code is making an assumption that isn't valid.
Your failing test case is essentially the following code:
{{{
zipcodes = Zipcode.objects.filter(people = self.bob)
print zipcodes[0]
print zipcodes[1]
}}}
You are assuming that zipcodes is an ordered list, and that you are
indexing into that list. You aren't. Zipcodes is an unevaluated queryset.
The queryset is evaluated twice - once for each subscript.`zipcodes[0]`
translates to the SQL query:
{{{
SELECT * from testapp_zipcode LIMIT 1;
}}}
... and `zipcodes[1]` translates to:
{{{
SELECT * from testapp_zipcode LIMIT 1 OFFSET 1;
}}}
Zipcodes doesn't have any inherent ordering, so there is no guarantee that
the database will return zipcode objects in the same order for the two
queries. As a result, you are seeing id=2 returned for both queries.
This won't even be 100% reproducible - it really does depend on the
internals of the database at the time you run the two queries. The
inconsistency between databases is one example of how this problem can
manifest.
There are several ways you can fix your code:
1. Put an order_by() clause on your query
2. Put an ordering clause in the Meta definition for the Zipcode model
3. Fully evaluate the query before indexing into it (i.e.,
list(zipcode.values()). By forcing the query to be evaluated, the index
operators will operate on the cached result of the full queryset, rather
than issuing two individual queries.
--
Ticket URL: <http://code.djangoproject.com/ticket/12615#comment:1>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.