Single django queryset to get n adjacent items

2019-07-10 05:01发布

问题:

I'm making an "infinite"/continuous scrolling list (like twitter) and want to be able to navigate to a specific item. Finding the item is straight forward, but I need to get a few items before and after it.

I'm using a similar approach to the answers suggested here: Getting next and previous objects in Django

before = list(reversed(models.MyModel.objects.filter(pk__lt=pk).order_by('-pk')[:10]))
after = list(models.MyModel.objects.filter(pk__gte=pk).order_by('pk')[:11])
objects = before + after

Is there any way to combine these into the one query?

I can't simply combine the two with the | operator, such as before | after and without list/reverse, as the slice must come first. I also can't do something like pk__lt=pk+10, pk__gt=pk-10 as objects may be deleted.

For a more complex example, if I was ordering by something other than the primary key I'd need to grab the object first with yet another query:

object = get_object_or_404(models.MyModel, pk=pk)
before = list(reversed(models.MyModel.objects.filter(pk__lt=object.other_key).order_by('-other_key')[:10]))
after = list(models.MyModel.objects.filter(pk__gte=object.other_key).order_by('other_key')[:11])
objects = before + after

Likewise, is it possible to accomplish the same thing with a single query?

回答1:

I once had a similar problem and solved it the way described here: defining an SQL-variable that describes the objects' order, and then ordering by that. However, that's plain SQL. I don't know if there's a way using the Django ORM.