How Can I Paginate Get_context_data Choosing From Among Multiple Context Objects?
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:
class SearchResultsAdvancedView(django.views.generic.ListView):
template_name = 'ephemera/searchresults_advanced.html'
form = AdvSearchForm()
paginate_by = 10
model = Item
def item_type(self):
choose_collection = self.request.GET.get('choose_collection')
if choose_collection != 'All' or not self.request.GET.get('user_input'):
return None
choose_item = self.request.GET.get('choose_item')
if choose_item in ('book', 'image'):
return choose_item
return None
def get_queryset(self, *args, **kwargs):
item_type = self.get_item_type()
qs = super.get_queryset(*args, **kwargs)
if item_type is not None:
return qs.filter(material_type__iexact=item_type)
return qs.none()
def get_context_object_name(self, object_list):
item_type = self.get_item_type()
if item_type is not None:
return '{}_qs'.format(item_type)
return super().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]:
def get_context_data(self, *, object_list=None, **kwargs):
"""Get the context for this view."""
queryset = object_list if object_list is not None else 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 is not None:
context[context_object_name] = queryset
context.update(kwargs)
return super().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.
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
class SearchResultsAdvancedView(django.views.generic.ListView):
template_name = 'ephemera/searchresults_advanced.html'
form = AdvSearchForm()
paginate_by = 10
model = Item
def get_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 = False
if 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 = True
elif 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?"