#从现在起,我们将在 board_topics 这个视图中来操作。
python manage.py shell
from django.contrib.auth.models import User
from boards.models import Board, Topic, Post
user = User.objects.first()
board = Board.objects.get(name='Django')
for i in range(100):
subject = 'Topic test #{}'.format(i)
topic = Topic.objects.create(subject=subject, board=board, starter=user)
Post.objects.create(message='Lorem ipsum...', topic=topic, created_by=user)
#在我们返回去写代码之前,让我们用 python shell 来做一些更多的实验:
python manage.py shell
from boards.models import Topic
Topic.objects.count()
Topic.objects.filter(board__name='Django').count()
queryset = Topic.objects.filter(board__name='Django').order_by('-last_updated')
#定义一个你要分页的查询集(QuerySet)的排序是很重要的。否则,会返回给你错误的结果。
#现在让我们导入 Paginator 工具:
from django.core.paginator import Paginator
paginator = Paginator(queryset, 20)
#这里我们告诉Django将查询集按照每页20个元素分页。
paginator.count
paginator.num_pages
paginator.page_range
paginator.page(2)
page = paginator.page(2)
type(page)
type(paginator)
#我们来简单看一下 Page 类提供的属性和方法:
page = paginator.page(1)
page.has_next()
page.has_previous()
page.has_other_pages()
page.next_page_number()
#这里是我们如何使用 FBV 来实现分页:
#boards/views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def board_topics(request, pk):
board = get_object_or_404(Board, pk=pk)
queryset = board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
page = request.GET.get('page', 1)
paginator = Paginator(queryset, 20)
try:
topics = paginator.page(page)
except PageNotAnInteger:
topics = paginator.page(1)
except EmptyPage:
topics = paginator.page(paginator.num_pages)
return render(request, 'topics.html', {'board': board, 'topics': topics}) 在 topics HTML列表的基础上,我们可以渲染分页组件:
<!--templates/topics.html-->
{% if topics.has_other_pages %}
<nav aria-label="Topics pagination" class="mb-4">
<ul class="pagination">
{% if topics.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ topics.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Previous</span>
</li>
{% endif %}
{% for page_num in topics.paginator.page_range %}
{% if topics.number == page_num %}
<li class="page-item active">
<span class="page-link">
{{ page_num }}
<span class="sr-only">(current)</span>
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
</li>
{% endif %}
{% endfor %}
{% if topics.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ topics.next_page_number }}">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Next</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
#GCBV 分页
#下面,相同的实现,但这次使用ListView。
#boards/views.py
class TopicListView(ListView):
model = Topic
context_object_name = 'topics'
template_name = 'topics.html'
paginate_by = 20 def get_context_data(self, **kwargs):
kwargs['board'] = self.board
return super().get_context_data(**kwargs)
def get_queryset(self):
self.board = get_object_or_404(Board, pk=self.kwargs.get('pk'))
queryset = self.board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
return queryset #myproject/urls.py
url(r'^boards/(?P<pk>\d+)/$', views.TopicListView.as_view(), name='board_topics'), #templates/topics.html
{% block content %}
<div class="mb-4">
<a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
</div>
<table class="table mb-4">
<!-- table content suppressed -->
</table>
{% if is_paginated %}
<nav aria-label="Topics pagination" class="mb-4">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Previous</span>
</li>
{% endif %}
{% for page_num in paginator.page_range %}
{% if page_obj.number == page_num %}
<li class="page-item active">
<span class="page-link">
{{ page_num }}
<span class="sr-only">(current)</span>
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Next</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endblock %}
#可复用的分页模板
#就像我们在 form.html 中封装模板时做的一样,我们也可以为分页的HTML代码片创建类似的东西。
#我们来对主题帖子页面进行分页,进而找到一种复用分页组件的方法法。
#boards/views.py
class PostListView(ListView):
model = Post
context_object_name = 'posts'
template_name = 'topic_posts.html'
paginate_by = 2
def get_context_data(self, **kwargs):
self.topic.views += 1
self.topic.save()
kwargs['topic'] = self.topic
return super().get_context_data(**kwargs)
def get_queryset(self):
self.topic = get_object_or_404(Topic, board__pk=self.
kwargs.get('pk'), pk=self.kwargs.get('topic_pk'))
queryset = self.topic.posts.order_by('created_at')
return queryset #更新一下 url.py
url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/$', views.PostListView.as_view(), name='topic_posts'), 现在,我们从topics.html模板中获取分页部分的html代码片,
并在templates/includes 文件夹下面创建一个名为 pagination.html 的新文件,
和 forms.html 同级目录:
#templates/includes/pagination.html
{% if is_paginated %}
<nav aria-label="Topics pagination" class="mb-4">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Previous</span>
</li>
{% endif %}
{% for page_num in paginator.page_range %}
{% if page_obj.number == page_num %}
<li class="page-item active">
<span class="page-link">
{{ page_num }}
<span class="sr-only">(current)</span>
</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<span class="page-link">Next</span>
</li>
{% endif %}
</ul>
</nav>
{% endif %} #现在,我们在 topic_posts.html 文件中来使用它:
#templates/topic_posts.html
{% block content %}
<div class="mb-4">
<a href="{% url 'reply_topic' topic.board.pk topic.pk %}"class="btn btn-primary" role="button">Reply</a>
</div>
{% for post in posts %}
<div class="card {% if forloop.last %}mb-4{% else %}mb-2{% endif %} {% if forloop.first %}border-dark{% endif %}">
{% if forloop.first %}
<div class="card-header text-white bg-dark py-2 px-3">{{ topic.subject }}</div>
{% endif %}
<div class="card-body p-3">
<div class="row">
<div class="col-2">
<img src="{% static 'img/avatar.svg' %}" alt="{{post.created_by.username }}" class="w-100">
<small>Posts: {{ post.created_by.posts.count }}</small>
</div>
<div class="col-10">
<div class="row mb-3">
<div class="col-6">
<strong class="text-muted">{{ post.created_by.username }}</strong>
</div>
<div class="col-6 text-right">
<small class="text-muted">{{ post.created_at}}</small>
</div>
</div>
{{ post.message }}
{% if post.created_by == user %}
<div class="mt-3">
<a href="{% url 'edit_post' post.topic.board.pk post.topic.pk post.pk %} "class="btn btn-primary btn-sm" role="button">Edit</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% include 'includes/pagination.html' %}
{% endblock %}
我们同样也可以更新一下先前的模板,topics.html 模板同样也可以这个封装的分页模板。
#templates/topics.html
{% block content %}
<div class="mb-4">
<a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
</div>
<table class="table mb-4">
<!-- table code suppressed -->
</table>
{% include 'includes/pagination.html' %}
{% endblock %}

Django入门与实践-第23章:分页实现(完结)的更多相关文章

  1. Django入门与实践-第15章:用户注销(完结)

    # myproject/settings.py LOGOUT_REDIRECT_URL = 'home' http://127.0.0.1:8000/logout/ # myproject/urls. ...

  2. Django入门与实践-第26章:个性化工具(完结)

    http://127.0.0.1:8000/boards/1/topics/62/reply/ 我觉得只添加内置的个性化(humanize)包就会很不错. 它包含一组为数据添加“人性化(human t ...

  3. Django入门与实践-第14章:用户注册(完结)

    http://127.0.0.1:8000/signup/ django-admin startapp accounts INSTALLED_APPS = [ 'accounts', ] # mypr ...

  4. Django入门与实践-第13章:表单处理(完结)

    http://127.0.0.1:8000/boards/1/ http://127.0.0.1:8000/boards/2/ http://127.0.0.1:8000/boards/3/ http ...

  5. Django入门与实践-第12章:复用模板(完结)

    http://127.0.0.1:8000/http://127.0.0.1:8000/boards/1/http://127.0.0.1:8000/boards/2/http://127.0.0.1 ...

  6. Django入门与实践-第11章:URL 分发(完结)

    http://127.0.0.1:8000http://127.0.0.1:8000/boards/1/http://127.0.0.1:8000/boards/2/http://127.0.0.1: ...

  7. Django入门与实践-第25章:Markdown 支持(完结)

    http://127.0.0.1:8000/boards/1/topics/102/reply/ 让我们在文本区域添加 Markdown 支持来改善用户体验. 你会看到要实现这个功能非常简单. 首先, ...

  8. Django入门与实践-第24章:我的账户视图(完结)

    http://127.0.0.1:8000/settings/account/ #好的,那么,这部分将是我们最后的一个视图.之后,我们将专心来改进现有功能. #accounts/views.py fr ...

  9. Django入门与实践-第22章:基于类的视图

    http://127.0.0.1:8000/boards/1/topics/2/posts/2/edit/ http://127.0.0.1:8000/ #boards/views.py from d ...

随机推荐

  1. SpringMvc Intercetor

    对于登录的访问控制以及session的超时控制. 当用户在未登录情况下,直接在地址栏输入url进入某些页面时,会越过登录页,如果不做控制会有安全问题. 因此可添加拦截器处理异常: /** * @Des ...

  2. chrome 常用插件下载安装

    可在google的应用商店进行下载:chrome://apps/ 但大多时间无法链接. 国内插件下载地址: http://www.cnplugins.com http://chromecj.com/ ...

  3. 管道限流利器pv

    pv 是什么 可不是 page view,是pipe viewer,管道偷窥器的缩写.这个东西的源站点在google code上,需要的话可以访问pv 的官网 . 这个东西的官方手册页(man pv或 ...

  4. COM组件三大接口IUnknown、IClassFactory、IDispatch。

    转自:http://blog.csdn.net/chenyujing1234/article/details/7753863 (1)COM组件有三个最基本的接口类,分别是IUnknown.IClass ...

  5. mysql 列转行

    第一种方法:使用序列化表的方法实现列转行 第一种方法:使用UNION的方法实现列转行 第二种方法:使用序列化表的方法实现列转行

  6. java.lang.NullPointerException - 如何处理空指针异常

    当应用程序试图null在需要对象的情况下使用时抛出.这些包括: 调用null对象的实例方法. 访问或修改null对象的字段. 把长度null当作一个数组. 像访问或修改null阵列一样访问或修改插槽. ...

  7. Wilcoxon Signed Rank Test

    1.Wilcoxon Signed Rank Test Wilcoxon有符号秩检验(也称为Wilcoxon有符号秩和检验)是一种非参数检验.当统计数据中使用“非参数”一词时,并不意味着您对总体一无所 ...

  8. 【vs2010】转换到 COFF 期间失败: 文件无效或损坏

    不知怎么本来编译好好的VS2010环境,忽然出现“转换到COFF 期间失败:文件无效或损坏”的链接错误.花了好多天,试了好多方法,最终解决了这个问题. 现在罗列一下这几种解决方案: 方案1:      ...

  9. URL传入带有%的参数的解决方法

    在参数中含有%时,需要将其转义为它的编码格式%25 ,后面跟对应字符的ASCII(16进制)码值 如我想要传入参数mm=75%到后台,就需要对%进行编码为%25,所以实际输入的参数是mm=75%25 ...

  10. java代码分析及分析工具

    一个项目从搭建开始,开发的初期往往思路比较清晰,代码也比较清晰.随着时间的推移,业务越来越复杂.代码也就面临着耦合,冗余,甚至杂乱,到最后谁都不敢碰. 作为一个互联网电子商务网站的业务支撑系统,业务复 ...