-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Missing/duplicate records when using ordering
and LimitOffsetPagination
#6886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @pierremonico - it sounds like something is causing your queryset to become randomly ordered (hence the duplicate items across pages). Looking at the code for
I would try logging the sql queries to see if the event query looks sensible. |
Make sure your models have a default ordering field or pagination will return seemingly random ordering. This is documented more clearly for CursorPagination but applies to all pagination AFAIK.
|
If adding 'id' to the ordering then it likely means you have NULL |
I just also hit this issue, and it's not limited to It's almost impossible to create a reproducible test case for this, as you need to hit exactly the right conditions for your database engine to shuffle rows around between queries. In my case the load on the server seems to influence this (probably related to whether the data remains in the cache between the queries), but there might be other factors as well. Nevertheless, I think this is at least undesired behaviour and arguably a bug. Especially if you use Proposal to resolve this:
|
For those also hitting this problem, you can workaround it by configuring this class in the from rest_framework.filters import OrderingFilter
# Work around DRF issue #6886 by always adding the primary key as last order field.
class StableOrderingFilter(OrderingFilter):
def get_ordering(self, request, queryset, view):
ordering = super(StableOrderingFilter, self).get_ordering(request, queryset, view)
pk = queryset.model._meta.pk.name
if ordering is None:
return ('-' + pk, )
return list(ordering) + ['-' + pk] |
@oxan I am getting null in ordering, shouldn't it always return null as we are overriding the ordering ? As we have a flow where we don't apply order_by in queryset and did it only in CursorPagination by using orderding field
|
The ordering recommendations given for the CursorPagination scheme actually apply to all pagination schemes, an unsuspecting developer that implements the more common `LimitOffsetPagination` or `PageNumberPagination` classes is unlikely to be aware of the importance of consistent ordering. This commit moves the `Details and limitations` section out of the `CursorPagination` section and puts it as the very first subsection of the `Pagination` page so that it's one of the first things that developers see. Some examples of inconsistencies as well as how to deal with them are given, and an extra way to change the ordering of a paginated view is provided. Fixes encode#6886
Before this commit, Flaw objects are ordered by the created_dt column, which is not unique and can change, furthermore "hacks" have been performed on said column multiple times due to bugs in the past. In order for ordering to be stable and reproducible, at least one of the columns in the group by must be unique and never changing, otherwise stuff like DRF Pagination can break [1], leading to missing and or duplicate records. This commit also applies this ordering to Affect and Tracker objects since they have their own paginated endpoints too. [1] encode/django-rest-framework#6886 (comment)
Checklist
master
branch of Django REST framework.Steps to reproduce
/api/events/?limit=25&offset=0
/api/events/?limit=25&offset=25
/api/events/?limit=25&offset=50
Expected behavior
Since I have 61 records in my test database, each unique record should be displayed on one of the pages. E.g. the event with the event date should be visible on the first page.
Actual behavior
Some records are not visible on any of the pages, and some records are duplicated across pages. The total
count
on the response objects is 61 as expected. But some records are simply not displayed.Setting
ordering=['-event_date', 'id']
solves the problem.NB: my event model actually subclasses an abstract model that has many more fields. I don't know if that has an actual impact but I tried to simplify the example for this issue.
Thanks.
The text was updated successfully, but these errors were encountered: