如何对基于 Django 类的通用 ListView 使用分页?

如何在 Django 1.3中使用分页?

有关这方面的文件并不十分清楚。

  • 我的 views.py是什么?

  • 我的模板是什么?

  • 我的 URLconf 文件是什么?

106802 次浏览

我认为您需要了解关于在新的基于类的视图中使用分页的信息,因为在传统的基于函数的视图中,很容易找到这些信息。我发现仅仅通过设置 paginate_by变量就足以激活分页。请看 基于类的通用视图

例如,在你的 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_paginatedpage_objpaginator)。

{# .... **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 中即可。

假设,我在 app/mods.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 文档 给你中添加了分页代码

应用程序/模板/应用程序/考试列表. 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'),
),
... ]

我们有两种方法来做到这一点。

第一个方法很简单,只需要设置类字段 paginate_by,不需要使用 get_context_data方法。

第二种方法有点复杂,但是我们可以更好地理解分页并定制复杂的分页或多个分页。让我看看。

这可以通过三个步骤来完成。

1. 重写 Viewget_context_data方法。

传递 page_keyspages,以便我们可以迭代列表并避免硬编码。

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

定制你的子 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 %}