1. #从现在起,我们将在 board_topics 这个视图中来操作。
  2. python manage.py shell
  3. from django.contrib.auth.models import User
  4. from boards.models import Board, Topic, Post
  5. user = User.objects.first()
  6. board = Board.objects.get(name='Django')
  7. for i in range(100):
  8. subject = 'Topic test #{}'.format(i)
  9. topic = Topic.objects.create(subject=subject, board=board, starter=user)
  10. Post.objects.create(message='Lorem ipsum...', topic=topic, created_by=user)
  1. #在我们返回去写代码之前,让我们用 python shell 来做一些更多的实验:
  2. python manage.py shell
  3. from boards.models import Topic
  4. Topic.objects.count()
  5. Topic.objects.filter(board__name='Django').count()
  6. queryset = Topic.objects.filter(board__name='Django').order_by('-last_updated')
  1. #定义一个你要分页的查询集(QuerySet)的排序是很重要的。否则,会返回给你错误的结果。
  2. #现在让我们导入 Paginator 工具:
  3. from django.core.paginator import Paginator
  4. paginator = Paginator(queryset, 20)
  5. #这里我们告诉Django将查询集按照每页20个元素分页。
  6. paginator.count
  7. paginator.num_pages
  8. paginator.page_range
  9. paginator.page(2)
  10. page = paginator.page(2)
  11. type(page)
  12. type(paginator)
  1. #我们来简单看一下 Page 类提供的属性和方法:
  2. page = paginator.page(1)
  3. page.has_next()
  4. page.has_previous()
  5. page.has_other_pages()
  6. page.next_page_number()
  1. #这里是我们如何使用 FBV 来实现分页:
  2. #boards/views.py
  3. from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
  4. def board_topics(request, pk):
  5. board = get_object_or_404(Board, pk=pk)
  6. queryset = board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
  7. page = request.GET.get('page', 1)
  8. paginator = Paginator(queryset, 20)
  9. try:
  10. topics = paginator.page(page)
  11. except PageNotAnInteger:
  12. topics = paginator.page(1)
  13. except EmptyPage:
  14. topics = paginator.page(paginator.num_pages)
  15. return render(request, 'topics.html', {'board': board, 'topics': topics})
  16.  
  17. topics HTML列表的基础上,我们可以渲染分页组件:
  18. <!--templates/topics.html-->
  19. {% if topics.has_other_pages %}
  20. <nav aria-label="Topics pagination" class="mb-4">
  21. <ul class="pagination">
  22. {% if topics.has_previous %}
  23. <li class="page-item">
  24. <a class="page-link" href="?page={{ topics.previous_page_number }}">Previous</a>
  25. </li>
  26. {% else %}
  27. <li class="page-item disabled">
  28. <span class="page-link">Previous</span>
  29. </li>
  30. {% endif %}
  31. {% for page_num in topics.paginator.page_range %}
  32. {% if topics.number == page_num %}
  33. <li class="page-item active">
  34. <span class="page-link">
  35. {{ page_num }}
  36. <span class="sr-only">(current)</span>
  37. </span>
  38. </li>
  39. {% else %}
  40. <li class="page-item">
  41. <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
  42. </li>
  43. {% endif %}
  44. {% endfor %}
  45. {% if topics.has_next %}
  46. <li class="page-item">
  47. <a class="page-link" href="?page={{ topics.next_page_number }}">Next</a>
  48. </li>
  49. {% else %}
  50. <li class="page-item disabled">
  51. <span class="page-link">Next</span>
  52. </li>
  53. {% endif %}
  54. </ul>
  55. </nav>
  56. {% endif %}
  1. #GCBV 分页
  2. #下面,相同的实现,但这次使用ListView。
  3. #boards/views.py
  4. class TopicListView(ListView):
  5. model = Topic
  6. context_object_name = 'topics'
  7. template_name = 'topics.html'
  8. paginate_by = 20
  9.  
  10. def get_context_data(self, **kwargs):
  11. kwargs['board'] = self.board
  12. return super().get_context_data(**kwargs)
  13. def get_queryset(self):
  14. self.board = get_object_or_404(Board, pk=self.kwargs.get('pk'))
  15. queryset = self.board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
  16. return queryset
  17.  
  18. #myproject/urls.py
  19. url(r'^boards/(?P<pk>\d+)/$', views.TopicListView.as_view(), name='board_topics'),
  20.  
  21. #templates/topics.html
  22. {% block content %}
  23. <div class="mb-4">
  24. <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
  25. </div>
  26. <table class="table mb-4">
  27. <!-- table content suppressed -->
  28. </table>
  29. {% if is_paginated %}
  30. <nav aria-label="Topics pagination" class="mb-4">
  31. <ul class="pagination">
  32. {% if page_obj.has_previous %}
  33. <li class="page-item">
  34. <a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
  35. </li>
  36. {% else %}
  37. <li class="page-item disabled">
  38. <span class="page-link">Previous</span>
  39. </li>
  40. {% endif %}
  41. {% for page_num in paginator.page_range %}
  42. {% if page_obj.number == page_num %}
  43. <li class="page-item active">
  44. <span class="page-link">
  45. {{ page_num }}
  46. <span class="sr-only">(current)</span>
  47. </span>
  48. </li>
  49. {% else %}
  50. <li class="page-item">
  51. <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
  52. </li>
  53. {% endif %}
  54. {% endfor %}
  55. {% if page_obj.has_next %}
  56. <li class="page-item">
  57. <a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
  58. </li>
  59. {% else %}
  60. <li class="page-item disabled">
  61. <span class="page-link">Next</span>
  62. </li>
  63. {% endif %}
  64. </ul>
  65. </nav>
  66. {% endif %}
  67. {% endblock %}
  1. #可复用的分页模板
  2. #就像我们在 form.html 中封装模板时做的一样,我们也可以为分页的HTML代码片创建类似的东西。
  3. #我们来对主题帖子页面进行分页,进而找到一种复用分页组件的方法法。
  4. #boards/views.py
  5. class PostListView(ListView):
  6. model = Post
  7. context_object_name = 'posts'
  8. template_name = 'topic_posts.html'
  9. paginate_by = 2
  10. def get_context_data(self, **kwargs):
  11. self.topic.views += 1
  12. self.topic.save()
  13. kwargs['topic'] = self.topic
  14. return super().get_context_data(**kwargs)
  15. def get_queryset(self):
  16. self.topic = get_object_or_404(Topic, board__pk=self.
  17. kwargs.get('pk'), pk=self.kwargs.get('topic_pk'))
  18. queryset = self.topic.posts.order_by('created_at')
  19. return queryset
  20.  
  21. #更新一下 url.py
  22. url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/$', views.PostListView.as_view(), name='topic_posts'),
  23.  
  24. 现在,我们从topics.html模板中获取分页部分的html代码片,
  25. 并在templates/includes 文件夹下面创建一个名为 pagination.html 的新文件,
  26. forms.html 同级目录:
  27. #templates/includes/pagination.html
  28. {% if is_paginated %}
  29. <nav aria-label="Topics pagination" class="mb-4">
  30. <ul class="pagination">
  31. {% if page_obj.has_previous %}
  32. <li class="page-item">
  33. <a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
  34. </li>
  35. {% else %}
  36. <li class="page-item disabled">
  37. <span class="page-link">Previous</span>
  38. </li>
  39. {% endif %}
  40. {% for page_num in paginator.page_range %}
  41. {% if page_obj.number == page_num %}
  42. <li class="page-item active">
  43. <span class="page-link">
  44. {{ page_num }}
  45. <span class="sr-only">(current)</span>
  46. </span>
  47. </li>
  48. {% else %}
  49. <li class="page-item">
  50. <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
  51. </li>
  52. {% endif %}
  53. {% endfor %}
  54. {% if page_obj.has_next %}
  55. <li class="page-item">
  56. <a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
  57. </li>
  58. {% else %}
  59. <li class="page-item disabled">
  60. <span class="page-link">Next</span>
  61. </li>
  62. {% endif %}
  63. </ul>
  64. </nav>
  65. {% endif %}
  66.  
  67. #现在,我们在 topic_posts.html 文件中来使用它:
  68. #templates/topic_posts.html
  69. {% block content %}
  70. <div class="mb-4">
  71. <a href="{% url 'reply_topic' topic.board.pk topic.pk %}"class="btn btn-primary" role="button">Reply</a>
  72. </div>
  73. {% for post in posts %}
  74. <div class="card {% if forloop.last %}mb-4{% else %}mb-2{% endif %} {% if forloop.first %}border-dark{% endif %}">
  75. {% if forloop.first %}
  76. <div class="card-header text-white bg-dark py-2 px-3">{{ topic.subject }}</div>
  77. {% endif %}
  78. <div class="card-body p-3">
  79. <div class="row">
  80. <div class="col-2">
  81. <img src="{% static 'img/avatar.svg' %}" alt="{{post.created_by.username }}" class="w-100">
  82. <small>Posts: {{ post.created_by.posts.count }}</small>
  83. </div>
  84. <div class="col-10">
  85. <div class="row mb-3">
  86. <div class="col-6">
  87. <strong class="text-muted">{{ post.created_by.username }}</strong>
  88. </div>
  89. <div class="col-6 text-right">
  90. <small class="text-muted">{{ post.created_at}}</small>
  91. </div>
  92. </div>
  93. {{ post.message }}
  94. {% if post.created_by == user %}
  95. <div class="mt-3">
  96. <a href="{% url 'edit_post' post.topic.board.pk post.topic.pk post.pk %} "class="btn btn-primary btn-sm" role="button">Edit</a>
  97. </div>
  98. {% endif %}
  99. </div>
  100. </div>
  101. </div>
  102. </div>
  103. {% endfor %}
  104. {% include 'includes/pagination.html' %}
  105. {% endblock %}
  1. 我们同样也可以更新一下先前的模板,topics.html 模板同样也可以这个封装的分页模板。
  2. #templates/topics.html
  3. {% block content %}
  4. <div class="mb-4">
  5. <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
  6. </div>
  7. <table class="table mb-4">
  8. <!-- table code suppressed -->
  9. </table>
  10. {% include 'includes/pagination.html' %}
  11. {% 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. html页面中iframe导致JavaScript失效

    <body onload=“reset()”> <div id="part1"> some thing here .... <div> < ...

  2. Java LinkedList的实现原理

    LinkedList是Java List类型的集合类的一种实现,此外,LinkedList还实现了Deque接口.本文基于Java1.8,对于LinkedList的实现原理做一下详细讲解. (Java ...

  3. Rust语言学习笔记(4)

    Variables and Mutability(变量和可变性) 变量声明有三种:不变量(运行期的常量),变量以及(编译期的)常量. 变量可以重复绑定,后声明的变量覆盖前面声明的同名变量,重复绑定时可 ...

  4. delphi实现映射和断开网络驱动器

    type TNetDiskMapper=class private FNetResource: TNetResource; FUserName,FPassWord:PWideChar; public ...

  5. java-- 的子类/父类构造方法 转

    前提:父类和子类同时都有有参的构造函数和无参构造函数. Java中的子类初始化时初值为空.调用顺序为先调用父类无参构造函数,然后调用子类无参构造函数. java中的子类初始化时初值不为空.调用顺序为先 ...

  6. C语言实现大数四则运算

    一.简介 众所周知,C语言中INT类型是有限制,不能进行超过其范围的运算,而如果采用float类型进行运算,由于float在内存中特殊的存储形式,又失去了计算的进度.要解决整个问题,一种解决方法是通过 ...

  7. 日志记录发布网站之后不成功,对路径“C:\Inetpub\wwwroot\***\***.xls”的访问被拒绝。

    主要是web程序的根目录文件夹路径访问权限不够,新增加一个everyone的完全控制读写的权限即可!---------折磨了两天,才发现使劲使错了地方. 另外: 一定谨记!!!!! 所写的路径如果不存 ...

  8. 基于MSAA的QQ界面信息获取的实现

    主要技术(Microsoft Active Accessibility)讲解: 以下是微软对于此技术的说明 Microsoft Active Accessibility Version 2.0 Pur ...

  9. python之面向对象之反射运用

    先看下hasattr和getattr在反射中的用法 import sys class apache(object): def __init__(self,tcp): self.tcp = tcp de ...

  10. 一个性能较好的JVM参数配置

    一个性能较好的web服务器jvm参数配置: -server//服务器模式-Xmx2g //JVM最大允许分配的堆内存,按需分配-Xms2g //JVM初始分配的堆内存,一般和Xmx配置成一样以避免每次 ...