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