1

Django pagination in TemplateView?

Hello, I am trying to figure out how I can access multiple models in a Class View and paginate at the same time.

My Outcome after reading, DjangoDoc and Stackoverflow:

ListView - I simply can use paginate_by= but I can load only one Model.

TemplateView - I can load many models but can not use paginate_by=?

For example three Models: Chicken, Cows and Cats (and I want to display on my page the last 3 entries of each model). All Models have a model field called entry date.

class HomeIndex(TemplateView):
   template_name = 'home.html'
   paginate_by = 3 # --- something like that

   def get_context_data(self, **kwargs):
      context = super(HomeIndex, self).get_context_data(**kwargs)
      context['chickens'] = Chicken.objects.order_by('-entry_date'')
      context['cows'] = Cows.objects.order_by('-entry_date'')
      context['cats'] = Cats.objects.order_by('-entry_date')

      return context

Or maybe I can add something to objects.order_by('-entry_date', < pagination? >).

Thanks

tk421
  • 5,775
  • 6
  • 23
  • 34
black_hole_sun
  • 908
  • 11
  • 41

2 Answers2

1

If you want to use ListView you still can, by chaining the querysets in get_queryset(self) and paginating that (read this answer to see the chain and sorted explained). This way you can use the default simple pagination.

from itertools import chain
from operator import attrgetter

class HomeIndex(ListView):
    template_name = 'home.html'
    paginate_by = 3 # --- somehting like that

    def get_queryset(self):
        chicken_list = Chicken.objects.all()
        cow_list = Cows.objects.all()
        cat_list = Cats.objects.all()

        result_list = sorted(
            chain(chicken_list, cow_list, cat_list),
            key=attrgetter('entry_date'),
            reverse=True)

        return result_list

Then in your template:

{% for data in object_list %}
    {{ data }} 
{% endfor %}

And you can use the pagination as shown here.

gdef_
  • 1,888
  • 9
  • 17
  • Interesting approach. Useful also for other cases. I tried to access the result_list via regular {% for data in result_list %} {{ data }} {% endfor %} but so far nothing shows up`? – black_hole_sun Feb 21 '19 at 15:40
  • Try accessing `{% for data in object_list %}` that is the default name for accessing the data from the template. Then you could use the default pagination object. I will update the answer. – gdef_ Feb 21 '19 at 16:06
1

Django QuerySet has built-in results slicing.

 Cows.objects.order_by('-entry_date'')[offset:limit]

For the last 3 entries, offset is 0 and the limit 3

 Cows.objects.order_by('-entry_date'')[0:3]

or the same can be written in a more pythonic way

 Cows.objects.order_by('-entry_date'')[:3]

To get last 3 cows, cats and chicken, following code will work.

def get_context_data(self, **kwargs):
    context = super(HomeIndex, self).get_context_data(**kwargs)
    context['chickens'] = Chicken.objects.order_by('-entry_date')[:3]
    context['cows'] = Cows.objects.order_by('-entry_date')[:3]
    context['cats'] = Cats.objects.order_by('-entry_date')[:3]


    return context

References:

  • Limiting Queries link
sun_jara
  • 1,736
  • 12
  • 20