Как я могу разбить get_context_data, выбирая из нескольких объектов контекста? - PullRequest
1 голос
/ 28 мая 2019

Я пытаюсь разбить get_context_data из views.py, выбирая из нескольких объектов контекста.В условных операторах примера кода показаны только два варианта, но у меня есть еще несколько вариантов, которые в основном охватывают все варианты из представления формы.Однако возвращается только один контекст, в конце концов, передавая контекст в представление шаблона для разбивки на страницы.

Я также попытался установить глобальную разбивку на страницы в settings.py, но она не работает.

Ранее я рассматривал приведенную ниже статью в качестве руководства по разбивке на страницы для объектов get-context-context.

Как выполнить разбиение на страницы для объекта контекста в django?

Из views.py:

from django.shortcuts import render
import django.views.generic
from django.http import HttpResponse
from django.template import loader
from django.template import RequestContext
from ephemera.models import *
from ephemera.serializers import ItemSerializer
from rest_framework import generics
from ephemera.forms import SearchForm, AdvSearchForm
from itertools import chain
from django.core.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':
            context['book_qs'] = 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':
            context['image_qs'] = Item.objects.raw('SELECT  * FROM   ephemera_item WHERE ephemera_item.material_type LIKE %s', ['image']);  
            imagepage = True

        if bookpage:
            paginator = Paginator(context, self.paginate_by)            
            page = self.request.GET.get('page')
            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:
            paginator = Paginator(context, self.paginate_by)            
            page = self.request.GET.get('page')
            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

Возвращены следующие ошибки:

Значение исключения: недоступный тип: 'slice'

Расположение исключения: c: \ users \ administrator \ appdata \ local \ Programs \ python \ python36-32 \ lib \ site-packages \ django \ core \ paginator.py на странице, строка 70

Ответы [ 2 ]

0 голосов
/ 31 мая 2019

Одной из проблем в исходном примере кода является то, что наборы RawQuerySets не работают для кода разбиения на страницы, показанного в get_context_data, и это должны быть объекты модели с фильтрами, иначе код разбиения на страницы потерпит неудачу. Ex.

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

В этом случае, однако, наборы RawQuerySets необходимы и полезны из-за дополнительных (не показаны) запросов со сложными внутренними объединениями и т. Д., Которые сложно выполнить с помощью фильтров.

Одно решение для приведения необработанного запроса в виде списка для разбиения на страницы ответили:

Также доступен модуль django paginator для RawQuerySet, чтобы помочь с этой проблемой, указанной в этом посте.

Джанго-Paginator-rawqueryset

С помощью модуля необработанные наборы запросов могут эффективно использоваться с заданным кодом разбиения на страницы, чтобы использовать объекты контекста для возврата контекста, который будет передан в шаблон. Затем шаблон вместе с типичным кодом для отображения навигации по страницам также может использовать переменные, связанные с контекстом, для отображения данных по мере необходимости.

    {% if book_qs %}
    {% endif %}

    {% if image_qs %}
    {% endif %}

Показанный пример проблемы из views.py является немного "грубой силой" и может быть закодирован более компактно с помощью определений в классе, как показано в первом ответе. Другое решение проблемы с использованием модуля показано здесь:

    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
0 голосов
/ 28 мая 2019

Нет необходимости использовать get_context_data [Django-doc] здесь, вы можете переопределить get_queryset [Django-doc] и get_context_object_name [Django-doc] , чтобы определить имя списка в вашем шаблоне:

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 <b>get_queryset</b>(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 <b>get_context_object_name</b>(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)

Логика Джанго будет разбивать на страницыQuerySet Сам, вам не нужно беспокоиться об этом.Это связано с get_context_data [Django-doc] реализацией 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:
        <b>paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)</b>
        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)

При этом у меня сложилось впечатление, что моделирование сделано не очень хорошо.Если у вас есть типы предметов, имеет смысл определить модель ItemType.Более того, лучше использовать ORM Django для генерации запросов, а не необработанных запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...