13 分页和shell命令行模式
技术交流QQ群:1027579432,欢迎你的加入!
本教程来源于B站杨仕航Django2.0开发视频教程,如需转载,必须注明来源!
1.为什么先讲分页功能
先讲分页功能,新增或编辑博客内容在admin后台操作.png
2.快速添加新的博客
- shell命令行模式下添加新博客:
-
python manage.py shell,如下图所示:
进入shell命令行模式.png - for循环执行新增博客代码
-
-
添加一篇新的博客,涉及到Blog这个模型。因此在shell命令行模式下导入Blog这个模型。再用dir()方法来查看模型是否成功导入。如下图所示:
导入Blog博客模型.png -
查询现有博客情况,如下图中的方法:
查询现有博客信息.png
3.模型新增对象
新增博客后的网页.png
>>> from blog.models import Blog >>> >>> >>> >>> Blog.objects.all() <QuerySet [<Blog: <Blog: 长内容的博客>>, <Blog: <Blog: 人物介绍>>, <Blog: <Blog: Django简 介>>] >>> Blog.objects.all().count() 3 >>> blog = Blog() >>> Blog.objects.all() <QuerySet [<Blog: <Blog: 长内容的博客>>, <Blog: <Blog: 人物介绍>>, <Blog: <Blog: Django简 介>>]> >>> blog.title = "shell模式下的第一篇博客" >>> blog.content = "这是一篇测试博客,233333333333333333333333333333333" >>> from blog.models import BlogType >>> dir() ['Blog', 'BlogType', '__builtins__', 'blog'] >>> BlogType.objects.all() <QuerySet [<BlogType: Django>, <BlogType: 随笔>, <BlogType: 感悟>]> >>> blog_type = BlogType.objects.all()[1] >>> blog.blog_type = blog_type >>> from django.contrib.auth.models import User >>> User.objects.all() <QuerySet [<User: CurryCoder>]> >>> User.objects.all() <QuerySet [<User: CurryCoder>]> >>> user = User.objects.all()[0] >>> blog.author = user >>> blog.save() >>> Blog.objects.all() <QuerySet [<Blog: <Blog: 长内容的博客>>, <Blog: <Blog: 人物介绍>>, <Blog: <Blog: Django简 介>>, <Blog: <Blog: shell模式下的第一篇博客>>]> >>> Blog.objects.all().count() 4 <!-- 查询blog对象的方法和属性 --> >>> dir(blog) ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_column_name_clashes', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering', '_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'author', 'author_id', 'blog_type', 'blog_type_id', 'check', 'clean', 'clean_fields', 'content', 'created_time', 'date_error_message', 'delete', 'from_db', 'full_clean', 'get_deferred_fields', 'get_next_by_created_time', 'get_next_by_last_updated_time', 'get_previous_by_created_time', 'get_previous_by_last_updated_time', 'id', 'last_updated_time', 'objects', 'pk', 'prepare_database_save', 'refresh_from_db', 'save', 'save_base', 'serializable_value', 'title', 'unique_error_message', 'validate_unique'] >>> blog.last_updated_time datetime.datetime(2020, 5, 13, 13, 44, 45, 113603, tzinfo=<UTC>)
- shell命令行模式下,快速添加大批量博客。具体效果如下如所示:
>>> for i in range(1,31): ... blog = Blog() ... blog.title = "for %s" % i ... blog.content = "这是for循环生成的第%s篇博客" % i ... blog.blog_type = blog_type ... blog.author = user ... blog.save() ... ... >>> Blog.objects.all().count() 34
shell命令行模式下,快速添加大批量博客.png
4.分页器实现分页
- 通过上图我们可以看出,当一下显示所有的博客时。因此实现分页功能,更便于我们查看想要浏览的博客。
>>> del Blog # 删除某个模型 >>> Blog Traceback (most recent call last): File "<console>", line 1, in <module> NameError: name 'Blog' is not defined >>> exit() >>> python manage.py shell >>> dir() ['__builtins__'] >>> from django.core.paginator import Paginator >>> from blog.models import Blog >>> Blog.objects.all() <QuerySet [<Blog: <Blog: 长内容的博客>>, <Blog: <Blog: 人物介绍>>, <Blog: <Blog: Django简 介>>, <Blog: <Blog: shell模式下的第一篇博客>>, <Blog: <Blog: for 1>>, <Blog: <Blog: for 2> >, <Blog: <Blog: for 3>>, <Blog: <Blog: for 4>>, <Blog: <Blog: for 5>>, <Blog: <Blog: for 6>>, <Blog: <Blog: for 7>>, <Blog: <Blog: for 8>>, <Blog: <Blog: for 9>>, <Blog: <Blog: for 10>>, <Blog: <Blog: for 11>>, <Blog: <Blog: for 12>>, <Blog: <Blog: for 13>>, <Blog: <Blog: for 14>>, <Blog: <Blog: for 15>>, <Blog: <Blog: for 16>>, '...(remaining elements truncated)...']> >>> blogs = Blog.objects.all() >>> blogs.count() 34 >>> paginator = Paginator(blogs, 10) <string>:1: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'blog.models.Blog'> QuerySet.
- 出现上面的UnorderedObjectListWarning错误,这是由于没有设置分页后每一页按照什么顺序排序。因此打开blog目录下的models.py文件,在Blog类下添加Meta类如下所示:
from django.db import models from django.contrib.auth.models import User # Create your models here. # 创建博文类型模型 class BlogType(models.Model): type_name = models.CharField(max_length=15) def __str__(self): return self.type_name # 创建博文模型 class Blog(models.Model): title = models.CharField(max_length=50) # 一篇博文属于一种类型,因此博客通过外键关联到博文类型 blog_type = models.ForeignKey(BlogType, on_delete=models.DO_NOTHING) content = models.TextField() author = models.ForeignKey(User, on_delete=models.DO_NOTHING) created_time = models.DateTimeField(auto_now_add=True) last_updated_time = models.DateTimeField(auto_now=True) def __str__(self): return "<Blog: %s>" % self.title <!-- 添加的新内容 --> class Meta: ordering = ['-created_time']
- 由于已经修改了Blog模型,所以要进行同步数据库。输入如下命令,如下图所示:
E:\Django\mysite_env\Scripts\mysite $ python manage.py makemigrations Migrations for 'blog': blog\migrations\0003_auto_20200513_2224.py - Change Meta options on blog E:\Django\mysite_env\Scripts\mysite $ python manage.py migrate Operations to perform: Apply all migrations: admin, auth, blog, contenttypes, sessions Running migrations: Applying blog.0003_auto_20200513_2224... OK E:\Django\mysite_env\Scripts\mysite $ python manage.py runserver Performing system checks... System check identified no issues (0 silenced). May 13, 2020 - 22:24:47 Django version 2.0, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.
- 退出之前的shell命令行模型,重新进入shell命令行模式下,输入如下代码:
>>> from django.core.paginator import Paginator >>> from blog.models import Blog >>> blogs = Blog.objects.all() >>> paginator = Paginator(blogs, 10) >>> paginator <django.core.paginator.Paginator object at 0x000000000469D978> >>> dir(paginator) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_object_list_is_ordered', '_get_page', 'allow_empty_first_page', 'count', 'get_page', 'num_pages', 'object_list', 'orphans', 'page', 'page_range', 'per_page', 'validate_number'] >>> paginator.__doc__ >>> paginator.count 34 >>> paginator.num_pages 4 >>> paginator.page_range range(1, 5) >>> >>> page1 = paginator.page(1) >>> page1 <Page 1 of 4> >>> dir(page1) ['__abstractmethods__', '__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', 'count', 'end_index', 'has_next', 'has_other_pages', 'has_previous', 'index', 'next_page_number', 'number', 'object_list', 'paginator', 'previous_page_number', 'start_index'] >>> page1.count <bound method Sequence.count of <Page 1 of 4>> >>> help(page1.count) Help on method count in module collections.abc: count(value) method of django.core.paginator.Page instance S.count(value) -> integer -- return number of occurrences of value >>> >>> page1.object_list [<Blog: <Blog: for 30>>, <Blog: <Blog: for 29>>, <Blog: <Blog: for 28>>, <Blog: <Blog: for 27>>, <Blog: <Blog: for 26>>, <Blog: <Blog: for 25>>, <Blog: <Blog: for 24>>, <Blog: <Blog: for 23>>, <Blog: <Blog: for 22>>, <Blog: <Blog: for 21>>] >>> page1.object_list.count <built-in method count of list object at 0x00000000046AFDC8>
分页器实现分页.png
5.分页的使用
- 前端页面:向后端服务器发送请求,请求打开具体的分页内容;
- 后端服务器:处理请求,返回具体分页内容响应请求;
- 例如,可以通过在浏览器中输入localhost:8000/blog/?page=1来访问第一页中的所有方法。因为前端通过url向服务器发送了GET请求,所以打开blog文件目录下的views.py文件,在blog_list()和blogs_with_type()函数中增加该请求对应的方法。views.py文件的内容如下:
from django.shortcuts import render_to_response, get_object_or_404 from django.core.paginator import Paginator from .models import Blog, BlogType # Create your views here. def blog_list(request): blogs_all_list = Blog.objects.all() paginator = Paginator(blogs_all_list, 10) # 每10篇进行一次分页 page_num = request.GET.get('page', 1) # 获取url的页码参数(GET请求) page_of_blogs = paginator.get_page(page_num) context = {} context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['blog_types'] = BlogType.objects.all() return render_to_response('blog/blog_list.html', context) 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): blogs_all_list = Blog.objects.all() paginator = Paginator(blogs_all_list, 2) # 每2篇进行一次分页 page_num = request.GET.get('page', 1) # 获取url的页码参数(GET请求) page_of_blogs = paginator.get_page(page_num) 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() context['page_of_blogs'] = page_of_blogs return render_to_response('blog/blogs_with_type.html', context)
- 接着,修改blog文件目录下的templates文件夹下的blog_list.html模板文件,经过views.py处理请求后,返回新的结果给前端页面。blog_list.html修改后的结果如下所示:
{% extends 'base.html' %} {# blog_list.html文件内容 #} {# 页面标题 #} {% block title %}我的网站{% endblock %} {% block nav_blog_active %}active{% endblock %} {% load staticfiles %} {% block header_extends %} <link rel="stylesheet" href="{% static 'blog/blog.css' %}"> {% endblock %} {# 页面内容 #} {% block content %} <div class="container"> <div class="row"> <div class="col-xs-12 col-sm-8 col-md-9 col-lg-10"> <div class="panel panel-default"> <div class="panel-heading"> {% block blog_list_title %}博客列表(一共有{{ page_of_blogs.paginator.count }}篇博客){% endblock %} </div> <div class="panel-body"> <!-- 下一行中的blogs来自于views.py中的context['blogs'] = Blog.objects.all() --> {% for blog in blogs %} <div class="blog"> <!-- 下一行中的blog.title来自于models.py中的title = models.CharField(max_length=50) --> <h3><a href="{% url 'blog_detail' blog.pk %}">{{ blog.title }}</a></h3> <p class="blog-info"> <span class="glyphicon glyphicon-tag"></span><a href="{% url 'blogs_with_type' blog.blog_type.pk %}">{{ blog.blog_type }}</a>     <span class="glyphicon glyphicon-time"></span>{{ blog.created_time|date:"Y-m-d" }} </p> <p>{{ blog.content|truncatechars:120 }}</p> </div> {% empty %} <div class="bog"> <h3>暂无博客,敬请期待</h3> </div> {% endfor %} </div> </div> <!-- 此处使用了bootstrp组件中的分页代码 --> <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> </div> <div class="hidden-xs col-sm-4 col-md-3 col-lg-2"> <div class="panel panel-default"> <div class="panel-heading"> 博客分类 </div> <div class="panel-body"> <ul class="blog-types"> {% for blog_type in blog_types %} <li><a href="{% url 'blogs_with_type' blog_type.pk %}">{{ blog_type.type_name }}</a></li> {% empty %} <li>暂无分类</li> {% endfor %} </ul> </div> </div> </div> </div> </div> {% endblock %}
添加分页按钮后的前端页面.png