13、分页和shell命令行模式
1、为什么先讲分页功能
- 1)新增或编辑博客内容
- 2)博客文章数较多–>全部加载过慢–>分页加载
- 为了夯实基础,借机讲shell模式、模型操作、模板标签、分页器
2、快速添加博客
- shell命令行模式添加博客
- (1)
python manage.py shell
- (2)for循环执行新增博客代码
3、模型新增对象
from blog.models import Blog
blog = Blog()
blog.title = "xxx"
...
blog.save()
打开项目文件夹,输入cmd进入命令行,
输入Scripts\activate
打开虚拟环境,
输入python manage.py shell
回车,
通过命令行界面演示如何添加一篇文章,
输入from blog.models import Blog
引入Blog,
输入dir()
查看可以看到Blog已经引入进来了,
输入Blog.objects.all()
找到所有博客,
也可以输入Blog.objects.count()
或者输入Blog.objects.all().count()
查博客数量。
输入blog = Blog()
将实例化结果赋值给blog变量,
然后dir()
查看当前环境就有blog对象了,但这个blog对象还没有保存到数据库,
输入Blog.objects.all()
还是只有三个,
我们需要添加一些东西,输入如下代码:
(这里可以对比models.py中Blog的各个字段来进行添加)
blog.title = "shell下第1篇"
blog.content = "xxxxx"
from blog.models import BlogType # 外键。类型需要引用进来
BlogType.objects.all()
BlogType.objects.all()[0]
blog_type= BlogType.objects.all()[0]
blog.blog_type = blog_type
from django.contrib.auth.models import User # 外键。User需要引用进来
User.objects.all()
user = User.objects.all()[0]
blog.author = user
blog.save() # 保存
Blog.objects.all() # 再查询
到目前为止,我们已经顺利在shell模式下创建了一篇文章,如果想在网页查看的话,可以再开启一个命令窗口,开启虚拟环境,然后python manage.py runserver
,访问http://localhost:8000/blog/
那我们如何知道blog的这些方法呢,我们可以通过dir(blog)
查看blog这个变量对象有哪些相关的方法
那一般可以用这样的代码在后台shell命令行这种模式下进行处理,那么我们同样可以用for循环一次性添加大量文章
在shell模式下输入代码:
for i in range(1, 31):
blog = Blog()
blog.title = "for %s" % i
blog.content = "xxxxx:%s" % i
blog.blog_type = blog_type
blog.author = user
blog.save()
然后输入Blog.objects.all().count()
查询一下数量。可以进入网页验证一下
这样,文章多的时候,我们一直往下拉加载文章,不太好,所以就产生了分页的需求,Django本身提供了分页器的分页功能。
4、分页器实现分页
- 分页器:
from django.core.paginator import Paginator
- 实例化:具体如何分页:
paginator = Paginator(object_list, each_page_count)
- 具体页面:
page1 = paginator.page(1)
from django.core.paginator import Paginator # 一般第一个单词大写的是 类
dir()
from blog.models import Blog
blogs = Blog.objects.all()
blogs.count()
paginator = Paginator(blogs, 10) # 第一个参数是具体的对象列表,第二个参数表示每页放10篇文章
这里回车之后,会出现一个警告,因为有些东西没有设置好。我们需要改动一下模型,因为我们模型没有一个默认的排序,所以不知道是不是每一页得到的内容不一样,所以这里最好根据一个排序规则来进行分页,修改blog/models.py如下,设置排列顺序:
然后在命令行输入python manage.py makemigrations
、python manage.py migrate
,同步数据库(一旦改动models.py,就需要同步迁移数据库),python manage.py runserver
重启服务,然后开启另外一个窗口重新输入:
python manage.py shell
from django.core.paginator import Paginator
from blog.models import Blog
blogs = Blog.objects.all()
paginator = Paginator(blogs, 10)
输入
paginator
dir(paginator)
可以查看paginator
的具体有什么东西(可以看到有count
、get_page
、num_pages
、object_list
、page
、page_range
、per_page
等属性或方法,后面陆续会用到)
输入paginator.count
能得到一个值,说明count
是一个属性;
再看一个,输入page1
,得到一个<>显示的内容,说明page1是一个方法,dir(page1)
可以看到用法有count
、object_list
、paginator
、has_previous
、has_next
、previous_page_number
、next_page_number
等,后面会使用到:
paginator.num_pages
page1 = paginator.page(1)
page1 # 它是一个方法
dir(page1)
page1.count
help(page1.count) # 可以查看这个方法的具体用法
page1.object_list
page1.object_list.count()
接下来我们就要开始设计分页
5、分页的使用
- 前端:发送请求,请求打开具体分页内容
- 后端:处理请求,返回具体分页内容响应请求
通过url传参数?page=1
,这个参数,跟views.py中的blog_pk、blog_type_pk参数是不一样的,这两个参数是django自动去识别url里面的链接对应的,而?page=1
这里的参数是不在这个识别范围内的,它是作为一种GET请求去发送,GET请求可以直接通过url看到具体发送了哪些参数、哪些参数值,它比较便捷,但它那个信息比较透明,而且发送的长度有限制。在页码这一块儿,用这个参数形式是很合适的。接下来我们就可以开始写后端的响应方法
修改blog/views.py代码如下:
# # C:\Users\12482\Desktop\py_learn\Django2.0_chapter46\mysite_env\mysite\blog\views.py
from django.shortcuts import render_to_response, get_object_or_404 # render_to_response:用模板页面输出响应内容
from django.core.paginator import Paginator
from .models import Blog, BlogType # 引入BlogType这个模型
# Create your views here.
# 需要两个处理方法:1.访问博客列表;2.显示具体的blog页面
def blog_list(request):
blogs_all_list = Blog.objects.all() # 获取所有博客
paginator = Paginator(blogs_all_list, 10) # 每10篇博客作为一页
page_num = request.GET.get('page', 1) # 获取页码参数(GET请求)。# 看有没有‘page’这个属性,如果没有,则默认给1
page_of_blogs = paginator.get_page(page_num) # 这里get_page方法,如果获取到的是其他字符而不是整数数字,会自动转化为1,使得它是处于有效的范围内
context = {}
# context['blogs'] = Blog.objects.all()
context['page_of_blogs'] = page_of_blogs # 修改。返回具体的博客给前端模板页面
context['blog_types'] = BlogType.objects.all()
# context['blogs_count'] = Blog.objects.all().count()
return render_to_response("blog/blog_list.html", context)
# 具体的blog页面需要传一个参数进来,这个参数就是主键id(主键pk)
def blog_detail(request, blog_pk):
context = {}
context['blog'] = get_object_or_404(Blog, pk=blog_pk)
return render_to_response('blog/blog_detail.html', context)
# 处理分类博客的页面的方法
def blogs_with_type(request, blog_type_pk):
context = {}
blog_type = get_object_or_404(BlogType, pk=blog_type_pk)
context['blog_type'] = blog_type # 该分类类型
context['blogs'] = Blog.objects.filter(blog_type=blog_type) # 筛选出该分类下博客
context['blog_types'] = BlogType.objects.all() # 网页右边“博客分类”栏里面,所有分类
return render_to_response("blog/blogs_with_type.html", context)
还需要改一下blog_list.html
访问http://localhost:8000/blog/?page=1:
这里我们还少了一个页面底部的页码,查看Bootstrap官网文档里面的“组件”——“分页”,然后修改blog_list.html如下:
【小技巧:粘贴对齐:复制后,按Ctrl+Alt+V 对齐粘贴】
<div>
<ul class="pagination">
{# 上一页 #}
<li>
{% if page_of_blogs.has_previous %}
<a href="?page={{ page_of_blogs.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
{% else %}
<span aria-hidden="true">«</span>
{% endif %}
</li>
{# 全部页码 #}
{% for page_num in page_of_blogs.paginator.page_range %}
<li><a href="?page={{ page_num }}">{{ page_num }}</a></li>
{% endfor %}
{# 下一页 #}
<li>
{% if page_of_blogs.has_next %}
<a href="?page={{ page_of_blogs.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
{% else %}
<span aria-hidden="true">»</span>
{% endif %}
</li>
</ul>
</div>
刷新页面:
这节课大概讲这么些内容,shell命令行模式,通过shell命令行模式怎么样去查对象有哪些方法和属性,怎么给模型创建对象,怎么给对象赋值,怎么保存。另外,再具体到分页器怎么使用,分页器有哪些方法和属性,分页器页面怎么设计,顺便讲了GET url请求,Bootstrap分页组件