Question

I written two django-cms plugins to display image galleries and videos.

These are attached to CMS pages at /gallery/ and /videos/ where each template has a placeholder allowing the corresponding plugin to be included.

At that base level where I have gallery.html and video.html rendering all plugin instances to the page I would like to be able to attach endless for pagination.

This was a really simple task to achive pagination on images within a gallery because I have an apphook view in the gallery to collect a list of all the images and then it's as simple as {% pagingate images %} {% for image in images %} etc in the template.

However in a template where django-cms controls the collection & rendering of all the plugin instances and I lose that control, how can I paginate the plugins?

I've started down a route of using an apphook on the /gallery/ index, but to acomplish this I can imagine I'll need to stop django-cms doing what it does by default and what it should be left to do. So I need some guidance/advise on the best method for the job. Anyway, here's some code;

# views.py
    def gallery_index(request, *args, **kwargs):

        template = request.current_page.template
        placeholder_id = request.current_page.placeholders.get(slot='gallery').id

        gallery = Placeholder.objects.get(id=placeholder_id)
        galleries = gallery.cmsplugin_set.all()

        return render_to_response(
            template,
            {'galleries': galleries},
            context_instance=RequestContext(request)
        )

# gallery.html
    <h3>GALLERIES</h3>

    <div id="panel-area" class="gallery_grid">
        <ul id="galleries" class="gridview" style="width: 800px;">
    {% paginate galleries %}
        {% for gallery in galleries %}
            <li>{{ gallery }}</li> <!-- testing the pagination -->
        {% endfor %}
    {% placeholder "gallery" %}
        </ul>
    {% show_pages %}

# cms_plugins.py
    class ImageGalleryPlugin(CMSPluginBase):

        name = _('Image Gallery')
        model = ImageGalleryPlugin
        form = ImageGalleryAdminForm
        render_template = 'single_gallery.html'

        def render(self, context, instance, placeholder):

            context.update({'gallery': instance,})        
            return context

# single_gallery.html
    <li class="gallery_top">
    <span class="title">
        <a href="{% url 'image_gallery_page' page_id=request.current_page.id gallery_id=gallery.id %}">{{ gallery.event_date|date:"d/m/Y" }}<br/>
             <p class="sub-text">View more of {{ gallery.event_name }}</p></a>
    </span>
        <img src="{{ gallery.display_random.gallery_display }}" alt="" border="0" />
    </li>

My current solution is a jQuery solution, but I'd love it all to be controlled by django endless pagination for consistency in behaviour and design.

Was it helpful?

Solution

Been there. Pagination in Django CMS plugin is indeed problematic.

One possible way to solve the problem

  1. Implement paginated API endpoint for fetching the objects. Use django.views.generic.list.ListView for example. It has nice built in pagination.
  2. In CMS plugin, fetch objects from the API endpoint with AJAX. CMS plugin doesn't need to know which objects to render, it just needs to know where it can fetch the objects (the API endpoint).

This approach requires frontend code for fetching the correct objects, updating the UI, keeping track of the current page and so on, but can be (and has been) successfully used to implement paginated Django CMS plugins.

OTHER TIPS

Here is my quick solution to add pagination into a django cms plugin

from cms.models.pagemodel import Page
from cms.plugin_base import CMSPluginBase
from django.http import Http404
from django.core.paginator import InvalidPage, Paginator


class MyPlugin(CMSPluginBase):

    def render(self, context, instance, placeholder):
        query_set = Page.objects.filter(is_page_type=False)
        page = context['request'].GET.get('page') or 1
        paginator, page, queryset, is_paginated = self.paginate_queryset(page, query_set, 6)
        context.update({'paginator': paginator,
                        'page_obj': page,
                        'is_paginated': is_paginated,
                        'object_list': queryset
                        })
        return context

    def paginate_queryset(self, page, queryset, page_size):
        paginator = Paginator(queryset, page_size)
        try:
            page_number = int(page)
        except ValueError:
            if page == 'last':
                page_number = paginator.num_pages
            else:
                raise Http404(_('Page is not “last”, nor can it be converted to an int.'))
        try:
            page = paginator.page(page_number)
            return (paginator, page, page.object_list, page.has_other_pages())
        except InvalidPage as e:
            raise Http404(_('Invalid page (%(page_number)s): %(message)s') % {
                'page_number': page_number,
                'message': str(e)
            })
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top