如何使用基于 Django 类的通用 ListViews 的分页?
Posted
技术标签:
【中文标题】如何使用基于 Django 类的通用 ListViews 的分页?【英文标题】:How do I use pagination with Django class based generic ListViews? 【发布时间】:2011-08-19 22:30:40 【问题描述】:如何在 Django 1.3 中使用分页?
文档对此不是很清楚。
我的views.py
怎么了?
我的模板有什么用?
我的 URLconf 文件中有什么内容?
【问题讨论】:
也许这篇博文会有所帮助:dontrepeatyourself.org/post/… 【参考方案1】:假设,我在 app/models.py 中有一个名为 FileExam(models.Model)
的类:
app/models.py
class FileExam(models.Model):
myfile = models.FileField(upload_to='documents/%Y/%m/%d')
date = models.DateTimeField(auto_now_add=True, blank=True)
teacher_name = models.CharField(max_length=30)
status = models.BooleanField(blank=True, default=False)
app/views.py
from app.models import FileExam
from django.core.paginator import Paginator
from django.core.paginator import EmptyPage
from django.core.paginator import PageNotAnInteger
class FileExamListView(ListView):
model = FileExam
template_name = "app/exam_list.html"
paginate_by = 10
def get_context_data(self, **kwargs):
context = super(FileExamListView, self).get_context_data(**kwargs)
list_exam = FileExam.objects.all()
paginator = Paginator(list_exam, self.paginate_by)
page = self.request.GET.get('page')
try:
file_exams = paginator.page(page)
except PageNotAnInteger:
file_exams = paginator.page(1)
except EmptyPage:
file_exams = paginator.page(paginator.num_pages)
context['list_exams'] = file_exams
return context
get_context_data
只做了一点改动,并添加了来自 django 文档here 的分页代码
app/templates/app/exam_list.html
正常内容列表
<table id="exam">
% for exam in list_exams %
<tr>
<td> exam.myfile </td>
<td> exam.date </td>
<td>.....</td>
</tr>
% endfor %
</table>
分页
% if is_paginated %
<ul class="pagination">
% if page_obj.has_previous %
<li>
<span><a href="?page= page_obj.previous_page_number ">Previous</a></span>
</li>
% endif %
<li class="">
<span>Page page_obj.number of page_obj.paginator.num_pages .</span>
</li>
% if page_obj.has_next %
<li>
<span><a href="?page= page_obj.next_page_number ">Next</a></span>
</li>
% endif %
</ul>
% else %
<h3>Your File Exam</h3>
<p>File not yet available</p>
% endif %
app/urls.py
urlpatterns = [
url(
r'^$', views.FileExamListView.as_view(), name='file-exam-view'),
),
... ]
【讨论】:
这看起来不对:context = super(SoalListView, self)...
。您的意思是:context = super(FileExamListView, self)...
?
是的,没错!此答案已由 Yacin 先生编辑。谢谢你,亚辛先生。
根据我的测试,我们不能像你一样拦截PageNotAnInteger
异常,因为如果我们通过GET
参数传递一个非整数ValueError
异常将在之前引发PageNotAnInteger
异常。这发生在ListView
类的paginate_queryset
方法级别。希望这很清楚【参考方案2】:
我们有两种方法可以做到这一点。
第一个很简单,只需设置类字段paginate_by
。 get_context_data
方法不需要我们做任何事情。
第二种方法有点复杂,但是我们可以对分页有更多的了解,并自定义复杂的分页或多个分页。来看看吧。
可以分三步完成。
1.重写View
的get_context_data
方法。
传递 page_keys
和 pages
以便我们可以迭代列表并避免硬编码。
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data()
df = pd.DataFrame(list(self.model.objects.all().values()))
ipc = df.groupby('ip')['ip'].count().sort_values(ascending=False)
urlc = df.groupby('url')['url'].count().sort_values(ascending=False).to_dict()
ipc = tuple(ipc.to_dict().items())
urlc = tuple(urlc.items())
pages = []
page_keys = ['page1', 'page2']
for obj, name in zip([urlc, ipc], page_keys):
paginator = Paginator(obj, 20)
page = self.request.GET.get(name)
page_ipc = obj
try:
page_ipc = paginator.page(page)
except PageNotAnInteger:
page_ipc = paginator.page(1)
except EmptyPage:
page_ipc = paginator.page(paginator.num_pages)
pages.append(page_ipc)
context['data'] = zip(pages, page_keys)
return context
2.自定义您的子template
。
我们定义了一些变量,以便我们可以遍历分页列表。
pagination.html
% if is_paginated %
<ul class="pagination">
% if page_obj.has_previous %
<li>
<span><a href="? pname = page_obj.previous_page_number ">Previous</a></span>
</li>
% endif %
<li class="">
<span>Page page_obj.number of page_obj.paginator.num_pages .</span>
</li>
% if page_obj.has_next %
<li>
<span><a href="? pname = page_obj.next_page_number ">Next</a></span>
</li>
% endif %
</ul>
% else %
<h3>Your File Exam</h3>
<p>File not yet available</p>
% endif %
3.自定义外层template
。
index.html
% for foo,name in data %
<div class="col-md-3 table-responsive">
% for k,v in foo %
<tr>
<th> forloop.counter </th>
<td> k </td>
<td> v </td>
</tr>
% endfor %
% include 'pagination.html' with pname=name page_obj=foo %
</div>
% endfor %
【讨论】:
【参考方案3】:我想您会询问有关在基于类的新视图中使用分页的信息,因为使用传统的基于函数的视图很容易找到。我发现只需设置paginate_by
变量就足以激活分页。请参阅Class-based generic views。
例如,在您的views.py
:
import models
from django.views.generic import ListView
class CarListView(ListView):
model = models.Car # shorthand for setting queryset = models.Car.objects.all()
template_name = 'app/car_list.html' # optional (the default is app_name/modelNameInLowerCase_list.html; which will look into your templates folder for that path and file)
context_object_name = "car_list" #default is object_list as well as model's_verbose_name_list and/or model's_verbose_name_plural_list, if defined in the model's inner Meta class
paginate_by = 10 #and that's it !!
在您的模板 (car_list.html
) 中,您可以包含这样的分页部分(我们有一些可用的上下文变量:is_paginated
、page_obj
和 paginator
)。
# .... **Normal content list, maybe a table** .... #
% if car_list %
<table id="cars">
% for car in car_list %
<tr>
<td> car.model </td>
<td> car.year </td>
<td><a href="/car/ car.id /" class="see_detail">detail</a></td>
</tr>
% endfor %
</table>
# .... **Now the pagination section** .... #
% if is_paginated %
<div class="pagination">
<span class="page-links">
% if page_obj.has_previous %
<a href="/cars?page= page_obj.previous_page_number ">previous</a>
% endif %
<span class="page-current">
Page page_obj.number of page_obj.paginator.num_pages .
</span>
% if page_obj.has_next %
<a href="/cars?page= page_obj.next_page_number ">next</a>
% endif %
</span>
</div>
% endif %
% else %
<h3>My Cars</h3>
<p>No cars found!!! :(</p>
% endif %
# .... **More content, footer, etc.** .... #
要显示的页面由 GET 参数指示,只需将 ?page=n
添加到 URL。
【讨论】:
没关系,但是你如何绑定模板也看到“car_list”对象? 仅供参考,您也可以直接在 urls.py:url(r'^cars/$', ListView.as_view( model=Car, paginate_by=10 )) 中执行此操作, 我学到的教训:要找到一种方法,在新选项卡中打开所有祖先类,然后 CTRL+F 去掉关键字。所以从docs.djangoproject.com/en/dev/ref/class-based-views/…,我们从基础教程中知道存在,打开所有祖先链接并搜索“pagi” 我一直在这样做,但我发现的问题是,当我对查询集中的对象进行额外处理时,它会将它们应用于数据库中的所有结果。因此,对于返回 100 个对象但每页仅显示 10 个对象的查询,将对 100 个对象进行额外处理。 我不喜欢硬编码的网址,您可以将其替换为:previous以上是关于如何使用基于 Django 类的通用 ListViews 的分页?的主要内容,如果未能解决你的问题,请参考以下文章
如何根据 Django 中当前基于类的通用视图模型向模板加载器添加路径