Search code examples
pythondjangodjango-queryset

Slices vs queryset in django


It all started with me trying to apply slices to a queryset to limit it. As I understand the documentation it is supposed to limit the results to 10 entries:

def get_queryset(self, *args, **kwargs):

    qs = Message.objects.all()  
    qs = qs.filter(Target_id=self.dialog)[:10]    # here the limit
    qs = qs.annotate(sender_id=Max('Sender__id')) 
    return qs

But really in template the request returns me all the records, but applies the annotation only to the first 10. I do not know why.

I thought the whole reason was annotate.

Then I remove the last line (with annotate). However I got in the template all the records instead of 10. That is same result as if I didn't make the slice.

In my template I'm not doing anything unusual: the iteration over the my queryset:

{% for message in messages %}
  {{message}}
{% endfor %}

This is weird: if I take len(qs) in my view, I get 10! But in template I get 300! It doesn't fit in my head.

I tried also to apply slice in the template instead of my view:

{% for message in messages|slice:":10" %}

But nothing has changed.

I have got all messages in my template instead of 10. How could this be?

PS: database type is sqlite.


Solution

  • It is documented that it is not advisable to futher modify a queryset after slicing [Django-doc]:

    Also note that even though slicing an unevaluated QuerySet returns another unevaluated QuerySet, modifying it further (e.g., adding more filters, or modifying ordering) is not allowed, since that does not translate well into SQL and it would not have a clear meaning either.

    You should change the order, like:

    def get_queryset(self, *args, **kwargs):
        return Message.objects.filter(Target_id=self.dialog).annotate(
            sender_id=Max('Sender__id')
        )[:10]

    So you first .filter(…) [Django-doc]/.annotate(…) [Django-doc], and then you slice.