技术交流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> &nbsp&nbsp&nbsp
                                        <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">&laquo;</span>
                                    </a>
                                {% else %}
                                    <span aria-hidden="true">&laquo;</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">&raquo;</span>
                                    </a>
                                {% else %}
                                    <span aria-hidden="true">&raquo;</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