Opened 17 years ago
Closed 17 years ago
#5012 closed (fixed)
Allow QuerySets to handle offsets without limits and negative slicing
Reported by: | Chris Beaven | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Keywords: | qs-rf-fixed | |
Cc: | cgrady@…, michael@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
This patch allows QuerySet
s to:
- use negative slicing (with the caveat that they require explicit ordering) and
- use offsets without limits (eg
Entries.objects.all()[5:]
)
So really it's two separate features, but negative slicing was the feature I was trying to implement and to make it work in a logical way it required fixing offsets without limits.
Feature 2 requires a change to the db backends. All except Oracle (because the comment in django.db.backends.oracle.base::get_limit_offset_sql
says it's handled in ./query.py
but that file doesn't exist) and MS-SQL (because it never worked there to begin with).
Attachments (3)
Change History (14)
by , 17 years ago
Attachment: | negative_sliced_querysets.patch added |
---|
comment:1 by , 17 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
comment:2 by , 17 years ago
comment:3 by , 17 years ago
That Oracle comment needs to be changed: the QuerySet subclass that was in query.py at one point wound up back in base.py. I'll take a look at supplying an Oracle patch for this.
by , 17 years ago
Attachment: | negative_sliced_querysets_oracle.patch added |
---|
Negative indexing patch of django/db/backends/oracle/base.py
comment:4 by , 17 years ago
One of the test cases for this is failing:
In [63]: Article.objects.all()[-5:-2][-1] --------------------------------------------------------------------------- <type 'exceptions.IndexError'> Traceback (most recent call last) /home/ikelly/projects/testproject/<ipython console> in <module>() /home/ikelly/projects/django.trunk/django/db/models/query.py in __getitem__(self, k) 216 try: 217 return list(self._clone(_offset=k, _limit=1, --> 218 **extra_clone_args))[0] 219 except self.model.DoesNotExist, e: 220 raise IndexError, e.args <type 'exceptions.IndexError'>: list index out of range
The sql that the Oracle backend is generating for this case is:
SELECT * FROM (SELECT "TEST_ARTICLE"."ID","TEST_ARTICLE"."HEADLINE","TEST_ARTICLE"."PUB_DATE", ROW_NUMBER() OVER (ORDER BY "TEST_ARTICLE"."PUB_DATE" DESC, "TEST_ARTICLE"."HEADLINE" DESC ) AS rn FROM "TEST_ARTICLE" ORDER BY "TEST_ARTICLE"."PUB_DATE" DESC, "TEST_ARTICLE"."HEADLINE" DESC) WHERE rn > -2 AND rn <= -1
This query will return no results due to the negative indices. Their presence in the SQL suggests that there's a bug in the way the negative indices are mapped in this case. The same test case also fails using the sqlite backend, but there it simply returns the wrong article rather than generating an error.
by , 17 years ago
Attachment: | negative_sliced_querysets_oracle.2.patch added |
---|
comment:5 by , 17 years ago
Cc: | added |
---|
comment:6 by , 17 years ago
Keywords: | qs-rf added |
---|
comment:7 by , 17 years ago
Cc: | added |
---|
comment:8 by , 17 years ago
comment:9 by , 17 years ago
comment:10 by , 17 years ago
Keywords: | qs-rf-fixed added; qs-rf removed |
---|---|
Triage Stage: | Design decision needed → Accepted |
Negative slicing isn't possible to implement in a way that is analogous with Python's behaviour without being fairly inefficient. The problem is you have to reverse the SQL query's order, limit the result set and then pull the results back into Python and reverse them again. That last step is the problem. We've just moved away from pulling results into memory until we need them (very important for large result sets), so adding it back just for this isn't worth it.
Instead, I've added a reverse() method to querysets so people can reverse and then slice off the front. It's close enough to negative slicing to provide all the same functionality, without being confusing by looking like Python slicing and not behaving precisely the same.
comment:11 by , 17 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
(In [7477]) Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
Finishing that last sentence of the topic: "... are included in the patch"