Skip to content Skip to sidebar Skip to footer

How Can I Paginate Get_context_data Choosing From Among Multiple Context Objects?

I am trying to paginate get_context_data from views.py, by selecting from among multiple context objects. Only two choices are shown in the code example conditional statements, bu

Solution 1:

There is no need to use get_context_data [Django-doc] here, you can override get_queryset [Django-doc] and get_context_object_name [Django-doc] to determine the name of the list in your template:

classSearchResultsAdvancedView(django.views.generic.ListView): 
    template_name = 'ephemera/searchresults_advanced.html'
    form = AdvSearchForm()
    paginate_by = 10
    model = Item

    defitem_type(self):
        choose_collection = self.request.GET.get('choose_collection')
        if choose_collection != 'All'ornot self.request.GET.get('user_input'):
            returnNone
        choose_item = self.request.GET.get('choose_item')
        if choose_item in ('book', 'image'):
            return choose_item
        returnNonedefget_queryset(self, *args, **kwargs):
        item_type = self.get_item_type()
        qs = super.get_queryset(*args, **kwargs)
        if item_type isnotNone:
            return qs.filter(material_type__iexact=item_type)
        return qs.none()

    defget_context_object_name(self, object_list):
        item_type = self.get_item_type()
        if item_type isnotNone:
            return'{}_qs'.format(item_type)
        returnsuper().get_context_object_name(object_list)

Django's logic will paginate the QuerySet itself, you thus do not need to worry about that. This is due to the get_context_data [Django-doc] implementation of the MultipleObjectMixin [Django-doc]:

defget_context_data(self, *, object_list=None, **kwargs):
    """Get the context for this view."""
    queryset = object_list if object_list isnotNoneelse self.object_list
    page_size = self.get_paginate_by(queryset)
    context_object_name = self.get_context_object_name(queryset)
    if page_size:
        paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
        context = {
            'paginator': paginator,
            'page_obj': page,
            'is_paginated': is_paginated,
            'object_list': queryset
        }
    else:
        context = {
            'paginator': None,
            'page_obj': None,
            'is_paginated': False,
            'object_list': queryset
        }
    if context_object_name isnotNone:
        context[context_object_name] = queryset
    context.update(kwargs)
    returnsuper().get_context_data(**context)

That being said, I have the impression that the modeling is not done very well. If you have types of items, it makes sence to define an ItemType model. Furthermore you better use Django's ORM to generate queries instead of raw queries.

Solution 2:

One problem in the original code example is the RawQuerySets do not work for the pagination code shown in get_context_data, and those should be model objects, with filters or else the pagination code will fail. Ex.

mydata = self.model.objects.filter(material_type__icontains = 'book')

In this case, however, the RawQuerySets, are needed and useful due to additional (not shown) queries with complex inner joins etc., difficult to accomplish with filters.

One solution for casting a raw query set as a list for pagination is answered in:

Also a django paginator module for RawQuerySet is available to help with this problem linked in that post.

django-paginator-rawqueryset

With the help of the module, the raw query sets can be used effectively with the given paginator code to utilize context objects for returning a context to be passed to the template. The template then, along with typical code to show the page navigation, is also able to utilize the variables attached to the context in order to display the data as needed.

    {% if book_qs %}
    {% endif %}

    {% if image_qs %}
    {% endif %}

The problem example shown, from views.py, is a bit 'brute force' and could be coded more compactly with the help of definitions within the class as shown in the first answer. Another solution to the problem, using the module, is shown here:

from rawpaginator.paginator import Paginator
    from django.core.paginator import EmptyPage
    from django.core.paginator import PageNotAnInteger


    classSearchResultsAdvancedView(django.views.generic.ListView): 
        template_name = 'ephemera/searchresults_advanced.html'
        form = AdvSearchForm()
        paginate_by = 10
        model = Item

        defget_context_data(self, **kwargs):       
            context = super(SearchResultsAdvancedView, self).get_context_data(**kwargs)

            choose_collection = self.request.GET.get('choose_collection')
            user_input = self.request.GET.get('user_input')
            choose_item = self.request.GET.get('choose_item')

            bookpage = False
            imagepage = Falseif choose_collection == 'All'and user_input == ''and choose_item == 'book':
                mydata = Item.objects.raw('SELECT  * FROM   ephemera_item WHERE ephemera_item.material_type LIKE %s', ['book']);    
                bookpage = Trueelif choose_collection == 'All'and user_input == ''and choose_item == 'image':
                mydata = Item.objects.raw('SELECT  * FROM   ephemera_item WHERE ephemera_item.material_type LIKE %s', ['image']);  
                imagepage = True

             paginator = Paginator(mydata, self.paginate_by)            
             page = self.request.GET.get('page')

            if bookpage:
                try:
                    book_qs = paginator.page(page)
                except PageNotAnInteger:
                    book_qs = paginator.page(1)
                except EmptyPage:
                    book_qs = paginator.page(paginator.num_pages)
                context['book_qs'] = book_qs

            elif imagepage:
                try:
                    image_qs = paginator.page(page)
                except PageNotAnInteger:
                    image_qs = paginator.page(1)
                except EmptyPage:
                    image_qs = paginator.page(paginator.num_pages)
                context['image_qs'] = image_qs

            return context

Post a Comment for "How Can I Paginate Get_context_data Choosing From Among Multiple Context Objects?"