Django DetailView中查询集的“下一步”和“上一步”按钮

Django DetailView中查询集的“下一步”和“上一步”按钮,django,Django,我是Django的新手,我正在做我的第一个真实(即非教程)项目。我有四个模型的基于类的列表视图,列表可以用各种方式过滤。用户可以单击筛选列表中的任何内容以获取项目的详细视图。这一切都很简单,效果很好 我希望在详细信息页面上有“上一步”和“下一步”按钮,允许用户以默认顺序(不是日期或id)逐步通过当前筛选集。我在StackOverflow和其他地方找到了各种看起来像是解决方案的一部分的零碎东西,但在我的观点中,我还没有弄清楚如何让它们一起工作 下面是我的一个表的稍微简化的代码。“作品”是指在两个剧

我是Django的新手,我正在做我的第一个真实(即非教程)项目。我有四个模型的基于类的列表视图,列表可以用各种方式过滤。用户可以单击筛选列表中的任何内容以获取项目的详细视图。这一切都很简单,效果很好

我希望在详细信息页面上有“上一步”和“下一步”按钮,允许用户以默认顺序(不是日期或id)逐步通过当前筛选集。我在StackOverflow和其他地方找到了各种看起来像是解决方案的一部分的零碎东西,但在我的观点中,我还没有弄清楚如何让它们一起工作

下面是我的一个表的稍微简化的代码。“作品”是指在两个剧院之一演出的各种物品(戏剧、歌剧、芭蕾舞等)

models.py

class Work(models.Model):

    title = models.CharField(max_length=100)
    sort_title = models.CharField(max_length=100)
    genre = models.CharField(max_length=50)

    class Meta:
        ordering = ['sort_title']
字段
sort\u title
去掉标题开头的文章(德语和法语),并处理重音字符等,以便标题按字母顺序正确排序。这是过滤集的顺序,我希望在“上一个”和“下一个”按钮中保留该顺序

views.py

class WorkList(ListView):
    context_object_name = 'works'
    model = Work
    paginate_by = 50
    template_name = 'works.html'

    def get_queryset(self):
        query = self.request.GET.get('q')
        if query is not None:
            return Work.objects.filter(Q(title__icontains=query))
        else:
            return Work.objects.all()

class WorkDetail(DetailView):
    context_object_name = 'work'
    model = Work
    template_name = 'work.html'
目前,用户只能按标题过滤作品,但我可以添加按流派过滤的可能性(因此,
Q
,我已经在其他视图中使用)。我使用的是Bootstrap 4,我会在细节页面的按钮上使用以下版本:

<ul class="pagination pt-3">
  <li class="page-link"><a href="#">Previous</a></li>
  <li class="page-link ml-auto"><a href="#">Next</a></li>
</ul>
但由于我还不知道如何使这项工作,我不知道什么网址将是

我已经试过了,在shell中效果很好,但是我不知道如何在我的视图中使它工作。因为我想从ListView中保留过滤后的queryset并在DetailView中使用它,所以我还尝试了在会话中保存queryset的这种方法:。但是我还没有弄清楚如何使用它在两个视图之间传递查询集

欢迎任何帮助

疑问 上一页:

Work.objects.filter(sort\u title\u lt=self.object.sort\u title).reverse().values('id')[:1]
下一页:

Work.objects.filter(sort\u title\u gt=self.object.sort\u title).值('id')[:1]
如果
sort_title
不唯一,则下一页-注意
gte
而不是
gt

Work.objects.filter(sort\u title\u gte=self.object.sort\u title).排除(id=self.object.id).值('id')[:1]
解释
  • 过滤器(…)
    默认情况下,
    工作
    对象按
    排序标题
    字段排序。因此,通过请求大于当前对象的
    sort\u title
    sort\u title
    ,我们将在集合中找到下一个
    Work
    对象
  • self.object
    是我们从
    DetailView
    访问当前对象的方式
  • values('id')
    仅选择我们需要的值来
    反转()
    URL到不同的
    工作细节。我假设这是
    id
    字段,但如果不是,可以用另一个字段替换
  • [:1]
    基本上只是将
    限制1
    添加到SQL查询中。我们只需要下一个
  • 这一切都使查询保持轻量级

    请注意,这些查询仅适用于上一页的
    \uu gt
    和下一页的
    \uu gt
    ,因为
    工作
    模型的默认顺序是按
    排序标题
    升序

    把它放在一起 考虑到您的
    ListView
    DetailView
    将共享相同的queryset逻辑,使用mixin可能是有意义的,例如:

    class WorkQueryMixin:
    def get_queryset(自我):
    query=self.request.GET.GET('q')
    如果查询不是无:
    返回Work.objects.filter(Q(title\uu icontains=query))
    其他:
    返回Work.objects.all()
    
    查询参数可以以不同的方式返回(例如,通过会话数据)

    将其置于上下文中,例如下一页:

    class WorkDetail(WorkQueryMixin, DetailView):
        context_object_name = 'work'
        model = Work
        template_name = 'work.html'
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            next_id = (
                self.get_queryset()
                .filter(sort_title__gt=self.object.sort_title)
                .values('id')[:1]
            )
            # There may be no next page
            if next_id:
                context['next_id'] = next_id[0]['id']
            return context
    
    非常感谢您提供了非常详细的初始答案,感谢您花时间指导我了解实施的细节。我现在有了功能性的“上一步”和“下一步”按钮,它们保留了当前的查询集。下面是我最后使用的代码,包括“上一步”和“下一步”按钮,并添加了一个类型过滤器:

    views.py
    
    class WorkQueryMixin:
        def get_queryset(self):
            query = self.request.GET.get('q')
            if query is not None:
                return Work.objects.filter(Q(title__icontains=query) | 
                      Q(genre__icontains=query))
            else:
                return Work.objects.all()
    
    class WorkList(WorkQueryMixin, ListView):
        context_object_name = 'works'
        model = Work
        paginate_by = 50
        template_name = 'my_app/works.html'
    
    class WorkDetail(WorkQueryMixin, DetailView):
        context_object_name = 'work'
        model = Work
        template_name = 'my_app/work.html'
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            prev_pk = (
                self.get_queryset()
                .filter(sort_title__lt=self.object.sort_title)
                .reverse().values('pk')[:1]
            )
            # There may be no next page
            if prev_pk:
                context['prev_pk'] = prev_pk[0]['pk']
        
            next_pk = (
                self.get_queryset()
                .filter(sort_title__gt=self.object.sort_title)
                .values('pk').values('pk')[:1]
            )
            # There may be no next page
            if next_pk:
                context['next_pk'] = next_pk[0]['pk']
        
            return context
    
    在Works列表视图的模板中,使用Bootstrap 4中的类:

    <ul>
      {% for work in works %}
        <a href="{% url 'my_app:work' work.pk %}?{{ 
          request.GET.urlencode }}" class="list-group-item list-group- 
          item-action">
            {% if work.title == "No title" %}
              {{work.title}}
            {% else %}
              <em>{{work.title}}</em>
            {% endif %} ({{work.genre}})
        </a>
      {% empty %}
        <p>No works match this search</p>
      {% endfor %}
    </ul>
    
      {%为在建工程%} {%empty%} 没有与此搜索匹配的作品

      {%endfor%}
    在工作详细信息视图的模板中:

    <ul class="pagination pt-3">
      {% if prev_pk %}
        <li class="page-link"><a href="{% url 'my_app:work' prev_pk %}?{{ 
            request.GET.urlencode }}">Previous</a></li>
      {% endif %}
      {% if next_pk %}
        <li class="page-link ml-auto"><a href="{% url 'my_app:work' next_pk 
            %}?{{ request.GET.urlencode }}">Next</a></li>
      {% endif %}
    </ul>
    
      {%if-prev_pk%}
    • {%endif%} {%if next_pk%}
    • {%endif%}

    我以前没有尝试过,但可能会奏效。您可以创建一个从工作列表继承的详细视图类,并对其逐个分页。基本上你的DetailView是一个列表视图,每页显示一个项目。非常感谢你的详细回答。我来看看我能不能让它工作!我刚刚意识到查询应该按
    sort\u title
    排序,而不是
    title
    。我将更新我的答案以反映这一点,谢谢。我正在努力使这项工作现在,但尚未成功。我没有任何混音的经验。如果我使用mixin,ListView应该是什么样子?在类定义中使用mixin,例如,
    类工作列表(ListView,WorkQueryMixin):
    类工作细节(DetailView,WorkQueryMixin):
    问题1已解决。根据,mixin名称必须位于视图名称的左侧: