Django 实现分页功能

准备

  1. 新建项目、app

  2. 准备数据库

    为了方便,直接用默认的sqlite了,目的是实现分页,写一个超级简单的模型就好。

    模型

    class Article(models.Model):
        title = models.CharField(max_length=100)
    

    视图

    用于随便添加几条数据

    def add_article(request):
        articles = []
        for i in range(250):
            articles.append(Article(title='文章%d' % i))
        Article.objects.bulk_create(articles)
        return HttpResponse('success')
    

分页

简单实现

可以直接利用Django内置的ListView做一个简单分页

视图

class ArticleView(ListView):
    model = Article
    template_name = 'list.html'
    context_object_name = 'articles'
    paginate_by = 10
    ordering = '-id'
    page_kwarg = 'page'

模板

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>文章列表</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<ul>
    {% for article in articles %}
        <li>{{ article.title }}</li>
    {% endfor %}
</ul>
<nav>
    <ul class="pagination">
        {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page_obj.previous_page_number }}">&laquo;</a>
            </li>
        {% endif %}
        {% for page in paginator.page_range %}
            {% if page == page_obj.number %}
                <li class="page-item active">
                    <a class="page-link" href="{% url 'list' %}?page={{ page }}">{{ page }}</a>
                </li>
            {% else %}
                <li class="page-item">
                    <a class="page-link" href="{% url 'list' %}?page={{ page }}">{{ page }}</a>
                </li>
            {% endif %}
        {% endfor %}
        {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page_obj.next_page_number }}">&raquo;</a>
            </li>
        {% endif %}
    </ul>
</nav>
</body>
</html>

很容易就运行出来了,但是哪里怪怪的,这个分页也太长了吧。

想象中的分页:

改进

重写ListViewget_context_data方法,在上下文中增加一些“自己的东西”。

class ArticleView(ListView):
    model = Article
    template_name = 'articles.html'
    context_object_name = 'articles'
    paginate_by = 10
    ordering = '-id'
    page_kwarg = 'page'

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        paginator = context['paginator']
        page_obj = context['page_obj']
        context.update(self.get_pagination_data(paginator, page_obj))
        return context

    @staticmethod
    def get_pagination_data(paginator, page_obj, around=2):
        """这个分页算法的核心部分,其实仔细看看也不难"""
        current = page_obj.number  # 当前页码
        total = paginator.num_pages  # 总共的页码
        if current <= around + 3:
            left_has_more = False
            left_page_range = range(1, current)
        else:
            left_has_more = True
            left_page_range = range(current - around, current)
        if current >= total - around - 2:
            right_has_more = False
            right_page_range = range(current + 1, total + 1)
        else:
            right_has_more = True
            right_page_range = range(current + 1, current + around + 1)
        return {
            'left_has_more': left_has_more,
            'right_has_more': right_has_more,
            'left_page_range': left_page_range,
            'right_page_range': right_page_range
        }

模板

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>文章列表</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<ul>
    {% for article in articles %}
        <li>{{ article.title }}</li>
    {% endfor %}
</ul>
<nav>
    <ul class="pagination justify-content-center">
        {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page_obj.previous_page_number }}">&laquo;</a>
            </li>
        {% endif %}

        {% if left_has_more %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page=1">1</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="javascript: void(0);">...</a>
            </li>
        {% endif %}

        {% for page in left_page_range %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page }}">{{ page }}</a>
            </li>
        {% endfor %}

        <li class="page-item active">
            <a class="page-link" href="javascript: void(0);">{{ page_obj.number }}</a>
        </li>

        {% for page in right_page_range %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page }}">{{ page }}</a>
            </li>
        {% endfor %}

        {% if right_has_more %}
            <li class="page-item">
                <a class="page-link" href="javascript: void(0);">...</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a>
            </li>
        {% endif %}

        {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="{% url 'list' %}?page={{ page_obj.next_page_number }}">&raquo;</a>
            </li>
        {% endif %}
    </ul>
</nav>
</body>
</html>

最终效果

posted @ 2020-03-19 16:19  毛珑珑  阅读(1140)  评论(1)    收藏  举报