9

Given a models.py:

class Partner(models.Model):
    ... (fields irrelevant to this example)

class Lecture(models.Model):
    ... (other fields not relevant to this example)
    partner models.ForeignKey(Partner)

I have a ListView for each and a DetailView for each (working fine).

The problem is that on the Partner DetailView page, I have the list of Lectures. In many cases this list can be quite long (e.g., >200), and the stakeholders want it to be paginated. I've had no problems with pagination on the ListView pages (that's easy), but I can't seem to figure out on the Partner's DetailView page how to paginate on their Lecture list.

I was hoping to see in the Django docs code that would look something like:

class PartnerDetailView(DetailView):
    model = Partner
    paginate_using = Lecture # (or something like self.lecture ?)
    paginate_by = 20

whereupon the DetailView would act on the single Partner object, but would (easily) allow pagination from the Lecture FK results.

Is there support for this? Or will it require far more custom view code (perhaps putting a 'page' variable in **kwargs for get_context_data() and creating the subset based on that)?

It just seems like a very common situation under CBVs so I'm puzzled why a search hasn't turned up any examples.

UPDATE: It should have occurred to me that a simple way to do this would be to just add a "page" piece to the url() entry that references the DetailView and use that to create the subset of pagination on the FK objects.

Note that this also might be a workable approach to getting around the "how do you paginate results from a FormView" issue...

Bob Donahue
  • 189
  • 2
  • 9

3 Answers3

8

Your best bet is probably to subclass ListView rather than DetailView, and override get_queryset to get the Lectures from the Partner. You can add the Partner object in get_context_data as well if you need it.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Thanks! It also occurred to me that I can just make an optional "page" part in the url() entry, and interpret that for creating the subset of lectures to show. (This should've been more obvious to me, and it also gets around a similar situation of paginating the results from a FormView that does search.) – Bob Donahue Aug 29 '14 at 14:03
  • thanks,i was in dilemma that it may violate beauty of cbv.but a guy with 235k reputation will be right – user1234567 Apr 17 '15 at 21:03
8

MultipleObjectMixin with DetailView

Hello. I would use MultipleObjectMixin and have pagination just like you did in ListView.

from django.views.generic.detail import DetailView
from django.views.generic.list import MultipleObjectMixin

class PartnerDetailView(DetailView,MultipleObjectMixin):
    model = Partner
    paginate_by = 5

    def get_context_data(self, **kwargs):
        object_list = Lecture.objects.filter(partner=self.get_object())
        context = super(PartnerDetailView, self).get_context_data(object_list=object_list, **kwargs)
        return context

Now in your template you can use object_list (all the lectures that are related to this partener) and use pagination.

{% if is_paginated %}
    {% include "includes/pagination.html" %}
{% endif %}

where in "includes/pagination.html" you have access to the pagination context(page_obj).

5

To extend @MsCheikh answer i will provide version without MultipleObjectMixin. Sample of my

class DealDetailView(DetailView):
    model = Deal
    template_name = "crm/deals/deal_detail.html"

    def get_context_data(self, **kwargs):
        context = super(DealDetailView, self).get_context_data(**kwargs)
        activities= self.get_related_activities()
        context['related_activities'] = activities
        context['page_obj'] = activities 
        return context

    def get_related_activities(self):
        queryset = self.object.activity_rel.all() 
        paginator = Paginator(queryset,5) #paginate_by
        page = self.request.GET.get('page')
        activities = paginator.get_page(page)
        return activities

So later i include standard Django pagination template (copied from docs) and iterate over related_activities

Maks
  • 1,527
  • 1
  • 13
  • 16
  • Though nowhere in Django Docs there is a mention of pagination for `DetailView`, got to your post and raised expectations!! Tried your example, however I am getting error at `queryset = self.object.activity_rel.all()` with caption `Attribute Error at: object has no attribute 'activity_rel'`. Can you help me resolve this issue? Thanks. – Love Putin Not War Mar 14 '22 at 01:08
  • @user12379095, activity_rel is a name from my code. I had a model Activity and relation to that model was called activity_rel. You should see the relations on your model. I can guide you to the official docs, or my older answer. https://stackoverflow.com/questions/3106295/django-get-list-of-model-fields/56713616#56713616 I am not current Django user, so can not answer from the top of my head – Maks Mar 16 '22 at 07:52