Django入门与实践-第23章:分页实现(完结)
#从现在起,我们将在 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章:分页实现(完结)的更多相关文章
- Django入门与实践-第15章:用户注销(完结)
# myproject/settings.py LOGOUT_REDIRECT_URL = 'home' http://127.0.0.1:8000/logout/ # myproject/urls. ...
- Django入门与实践-第26章:个性化工具(完结)
http://127.0.0.1:8000/boards/1/topics/62/reply/ 我觉得只添加内置的个性化(humanize)包就会很不错. 它包含一组为数据添加“人性化(human t ...
- Django入门与实践-第14章:用户注册(完结)
http://127.0.0.1:8000/signup/ django-admin startapp accounts INSTALLED_APPS = [ 'accounts', ] # mypr ...
- 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 ...
- 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 ...
- 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: ...
- Django入门与实践-第25章:Markdown 支持(完结)
http://127.0.0.1:8000/boards/1/topics/102/reply/ 让我们在文本区域添加 Markdown 支持来改善用户体验. 你会看到要实现这个功能非常简单. 首先, ...
- Django入门与实践-第24章:我的账户视图(完结)
http://127.0.0.1:8000/settings/account/ #好的,那么,这部分将是我们最后的一个视图.之后,我们将专心来改进现有功能. #accounts/views.py fr ...
- 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 ...
随机推荐
- Tocmat 启动错误 Port 8005 required by tomcat v7.0 server at localhost is already in use
1: netstat -ano!findstr 8005 2: taskkill /pid 6476 /f
- 基于OpenGL编写一个简易的2D渲染框架-03 渲染基本几何图形
阅读文章前需要了解的知识,你好,三角形:https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/ 要 ...
- spark性能调优 数据倾斜 内存不足 oom解决办法
[重要] Spark性能调优——扩展篇 : http://blog.csdn.net/zdy0_2004/article/details/51705043
- Mysql通过SQL脚本复制表
create table if not exists t_dest like t_src 其中,t_src是要复制的原始表,t_dest是要创建的新表.
- redis的五种常见数据类型的常用指令
一.String字符串,key-value 应用场景:string是redis的最基本数据类型,key-value格式,一个key对应一个值的情况下 1.设置key = value:set key ...
- padright padleft
在 C# 中可以对字符串使用 PadLeft 和 PadRight 进行轻松地补位. PadLeft(int totalWidth, char paddingChar) //在字符串左边用 paddi ...
- ftp上传下载工具类
package com.taotao.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNo ...
- Docker三剑客之 Compose
简介 Docker-Compose 是 Docker 的一种编排服务,是一个用于在 Docker 上定义并运行复杂应用的工具,可以让用户在集群中部署分布式应用. 通过 Docker-Compose 用 ...
- ElementTree 解析xml(minidom解析xml大文件时,MemoryError)
在使用minido解析xml文件时,因为文件过大,结果报错MemoryError.查询后得知是因为minidom在解析时是将所有文件放到内存里的,很占用内存,所以要考虑换一种方法来处理xml文件. ...
- 【c++】多层次继承类对象的构造函数参数的传递方法
#include <iostream.h> //基类CBase class CBase { int a; public: CBase(int na) { a=na; cout<< ...