13 分页功能
1. 为什么要分页功能
- 新增或编辑博客内容
- 博文数目较多 -> 全部加载过慢 -> 分页加载缓冲
- 夯实基础: 熟悉shell模型、模型操作、模板标签、分页器
2. 快速添加博文
shell命令行添加博文
python manage.py shell for 循环执行新增博文代码 exit()退出
3. 模型新增对象
from s2aclab.models import Articles article = Articles() article.title = ‘xxx’ … artclie.save()
dir() 查看变量的方法 dir(article) [‘DoesNotExist’, ‘MultipleObjectsReturned’, ‘class‘, ‘delattr‘, ‘dict‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getstate‘, ‘gt‘, ‘hash‘, ‘init‘, ‘init_subclass‘, ‘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’, ‘article_type’, ‘article_type_id’, ‘author’, ‘author_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’] article.last_updated_time datetime.datetime(2020, 6, 3, 7, 31, 7, 411026, tzinfo=)
>>> from s2aclab.models import Articles,ArticleType>>> from django.contrib.auth.models import User>>> a = Articles()>>> a_type = ArticleType.objects.all()[0]>>> user = User.objects.all()[0]>>> for i in range(1,30):... a = Articles()... a.title = "for %s" % i... a.content = "xxxx: %s" % i... a.article_type = a_type... a.author = user... a.save()...>>> Articles.objects.all().count()32>>>
4. 分页器实现分页 Paginator
分页器: from django.core.paginator import Paginator 实例化: 具体如何分页 paginator = Paginator(object_list, each_page_count) 具体页面 page1 = paginator.page(1)
>>> from django.core.paginator import Paginator
>>> from s2aclab.models import Articles
>>> dir()
['Articles', 'Paginator', '__builtins__']
>>> arts = Articles.objects.all()
>>> arts.count()
32
>>> paginator = Paginator(arts,10)
<string>:1: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 's2aclab.models.Articles'> QuerySet.
>>>
上面警告是因为没有设置默认的排序方式
在s2aclab.models.Articles类中新建类
class Meta: # 排序
ordering = ['-created_time']
然后更新同步迁移数据库,重新开启本地服务。再重新分页
>>> from django.core.paginator import Paginator
>>> from s2aclab.models import Articles
>>> arts = Articles.objects.all()
>>> arts.count()
32
>>> paginator = Paginator(arts,10)
>>> paginator
<django.core.paginator.Paginator object at 0x000001C8185B4400>
>>> dir(paginator)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__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.count
32
>>> 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__', '__init_subclass__', '__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']
http://localhost:8000/article/?page=2 GET请求访问页码
修改views.py
from django.core.paginator import Paginator
def articles_list(request):
articles_all_list = Articles.objects.all()
paginator = Paginator(articles_all_list, 10) # 10篇一页
# 获取页码参数(GET请求) .GET 字典 使用get方法判断是否有page值,没有返回1
page_num = request.GET.get("page", 1)
page_of_articles = paginator.get_page(page_num) # 输入许可字符范围外的字符会返回1
context = {}
# context['articles'] = page_of_articles.object_list # 前端页面
context['page_of_articles'] = page_of_articles
context['article_types'] = ArticleType.objects.all()
return render(request, 'articles_list.html', context)
修改articles_list.html
{% block article_list_title %}Blog List | {{ page_of_articles.paginator.count }} blogs{% endblock %}
{% for article in page_of_articles.object_list %}
<!-- 页码 -->
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
{% if page_of_articles.has_previous %}
<a href="?page={{ page_of_articles.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
{% else %}
<span aria-hidden="true">«</span>
{% endif %}
</li>
{% for page_index in page_of_articles.paginator.page_range %}
<li><a href="?page={{ page_index }}">{{ page_index}}</a></li>
{% endfor %}
<li>
{% if page_of_articles.has_next %}
<a href="?page={{ page_of_articles.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
{% else %}
<span aria-hidden="true">»</span>
{% endif %}
</li>
</ul>
</nav>
5. 页面优化
1. 当前页高亮 class="active"
2. 不要一次性展示过多的页码选择,影响页面布局
3. 公共参数放入项目的settings.py中。
5.1 当前页高亮
{% for page_index in page_range %}
{% if page_index == page_of_articles.number %}
<li class="active"><span>{{ page_index}}</span></li>
5.2 显示页码范围
views.py
def articles_list(request):
articles_all_list = Articles.objects.all()
paginator = Paginator(
articles_all_list, settings.ARTICLE_NUMBER_EACH_PAGE) # 4篇一页
# 获取页码参数(GET请求) .GET 字典 使用get方法判断是否有page值,没有返回1
page_num = request.GET.get("page", 1)
page_of_articles = paginator.get_page(page_num) # 输入许可字符范围外的字符会返回1
# 获取当前页
current_page = page_of_articles.number
# 页码显示范围
page_range = [i for i in range(current_page-2,current_page+3) if 0<i<=paginator.num_pages]
# 第一页
if page_range[0] >= 2:
page_range.insert(0, 1) # 第一位插入1页码
if page_range[1] != 2:
page_range.insert(1,'...') # 加上...
# 最后一页
if page_range[-1] <= paginator.num_pages - 1:
if page_range[-1] != paginator.num_pages - 1:
page_range.append('...') # 加上...
page_range.append(paginator.num_pages)
def article_with_type(request, art_type_pk):
article_type = get_object_or_404(ArticleType, pk=art_type_pk)
articles_all_list = Articles.objects.filter(article_type=article_type)
paginator = Paginator(
articles_all_list, settings.ARTICLE_NUMBER_EACH_PAGE) # 4篇一页
# 获取页码参数(GET请求) .GET 字典 使用get方法判断是否有page值,没有返回1
page_num = request.GET.get("page", 1)
# 输入许可字符范围外的字符会返回1
page_of_articles = paginator.get_page(page_num)
# 获取当前页
current_page = page_of_articles.number
# 页码显示范围
page_range = [i for i in range(
current_page-2, current_page+3) if 0 < i <= paginator.num_pages]
# 第一页
if page_range[0] >= 2:
page_range.insert(0, 1) # 第一位插入1页码
if page_range[1] != 2:
page_range.insert(1, '...')
# 最后一页
if page_range[-1] <= paginator.num_pages - 1:
if page_range[-1] != paginator.num_pages - 1:
page_range.append('...')
page_range.append(paginator.num_pages)
context = {}
# context['articles'] = page_of_articles.object_list # 前端页面
context['page_of_articles'] = page_of_articles # 当前页码
context['article_type'] = article_type
context['article_types'] = ArticleType.objects.all()
context['page_range'] = page_range
return render(request, 'articles_list.html', context)
articles_list.html
<div class="panel-heading">
{% block article_list_title %}Blog List | {{ page_of_articles.paginator.count }} blogs{% endblock %}
</div>
<!-- 页码 -->
<nav aria-label="Page navigation">
<ul class="pagination">
<li>
{% if page_of_articles.has_previous %}
<a href="?page={{ page_of_articles.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
{% else %}
<span aria-hidden="true">«</span>
{% endif %}
</li>
{% for page_index in page_range %}
{% if page_index == page_of_articles.number %}
<li class="active"><span>{{ page_index}}</span></li>
{% else %}
{% if page_index == '...' %}
<li><span>{{page_index}}</span></li>
{% else %}
<li><a href="?page={{ page_index }}">{{ page_index}}</a></li>
{% endif %}
{% endif %}
{% endfor %}
<li>
{% if page_of_articles.has_next %}
<a href="?page={{ page_of_articles.next_page_number }}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
{% else %}
<span aria-hidden="true">»</span>
{% endif %}
</li>
</ul>
</nav>
5.3 全局参数放入settings.py
# 自定义参数...............................................................................
ARTICLE_NUMBER_EACH_PAGE = 4
调用全局参数: from django.conf import settings
