Django

Code

Ticket #5012 (closed: fixed)

Opened 10 months ago

Last modified 3 weeks ago

Allow QuerySets to handle offsets without limits and negative slicing

Reported by: SmileyChris Assigned to: nobody
Component: Database wrapper Version: SVN
Keywords: qs-rf-fixed Cc: cgrady@the-magi.us, michael@elsdoerfer.info
Triage Stage: Accepted Has patch: 1
Needs documentation: 0 Needs tests: 0
Patch needs improvement: 0

Description

This patch allows QuerySets to:

1. use negative slicing (with the caveat that they require explicit ordering) and

2. 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

negative_sliced_querysets.patch (16.6 kB) - added by SmileyChris on 07/29/07 18:44:47.
negative_sliced_querysets_oracle.patch (2.9 kB) - added by ian.g.kelly@gmail.com on 08/03/07 13:43:31.
Negative indexing patch of django/db/backends/oracle/base.py
negative_sliced_querysets_oracle.2.patch (2.6 kB) - added by ian.g.kelly@gmail.com on 08/03/07 13:59:09.

Change History

07/29/07 18:44:47 changed by SmileyChris

  • attachment negative_sliced_querysets.patch added.

07/29/07 18:45:03 changed by SmileyChris

  • needs_better_patch changed.
  • stage changed from Unreviewed to Design decision needed.
  • needs_tests changed.
  • needs_docs changed.

07/29/07 18:46:14 changed by SmileyChris

Finishing that last sentence of the topic: "... are included in the patch"

08/03/07 11:33:51 changed by ian.g.kelly@gmail.com

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.

08/03/07 13:43:31 changed by ian.g.kelly@gmail.com

  • attachment negative_sliced_querysets_oracle.patch added.

Negative indexing patch of django/db/backends/oracle/base.py

08/03/07 13:52:41 changed by ian.g.kelly@gmail.com

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.

08/03/07 13:59:09 changed by ian.g.kelly@gmail.com

  • attachment negative_sliced_querysets_oracle.2.patch added.

08/03/07 15:39:46 changed by Collin Grady <cgrady@the-magi.us>

  • cc set to cgrady@the-magi.us.

09/14/07 13:34:46 changed by piranha

  • keywords set to qs-rf.

10/01/07 21:32:26 changed by miracle2k

  • cc changed from cgrady@the-magi.us to cgrady@the-magi.us, michael@elsdoerfer.info.

02/22/08 19:34:50 changed by mtredinnick

(In [7147]) queryset-refactor: Implemented slicing to end of querysets.

Refs #2150, #5012.

02/22/08 19:35:34 changed by mtredinnick

(In [7148]) queryset-refactor: Implemented the reverse() method on querysets.

Refs #5012.

02/22/08 19:38:44 changed by mtredinnick

  • keywords changed from qs-rf to qs-rf-fixed.
  • stage changed from Design decision needed to 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.

04/26/08 21:50:16 changed by mtredinnick

  • status changed from new to closed.
  • resolution set to fixed.

(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


Add/Change #5012 (Allow QuerySets to handle offsets without limits and negative slicing)




Change Properties
Action