larken

勤奋的人生才有价值

导航

Django入门与实践-第23章:分页实现(完结)

#从现在起,我们将在 board_topics 这个视图中来操作。
python manage.py shell
from django.contrib.auth.models import User
from boards.models import Board, Topic, Post
user = User.objects.first()
board = Board.objects.get(name='Django')
for i in range(100):
    subject = 'Topic test #{}'.format(i)
    topic = Topic.objects.create(subject=subject, board=board, starter=user)
    Post.objects.create(message='Lorem ipsum...', topic=topic, created_by=user)
#在我们返回去写代码之前,让我们用 python shell 来做一些更多的实验:
python manage.py shell
from boards.models import Topic
Topic.objects.count()
Topic.objects.filter(board__name='Django').count()
queryset = Topic.objects.filter(board__name='Django').order_by('-last_updated')
#定义一个你要分页的查询集(QuerySet)的排序是很重要的。否则,会返回给你错误的结果。
#现在让我们导入 Paginator 工具:
from django.core.paginator import Paginator
paginator = Paginator(queryset, 20)
#这里我们告诉Django将查询集按照每页20个元素分页。
paginator.count
paginator.num_pages
paginator.page_range
paginator.page(2)
page = paginator.page(2)
type(page)
type(paginator)
#我们来简单看一下 Page 类提供的属性和方法:
page = paginator.page(1)
page.has_next()
page.has_previous()
page.has_other_pages()
page.next_page_number()
#这里是我们如何使用 FBV 来实现分页:
#boards/views.py
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def board_topics(request, pk):
    board = get_object_or_404(Board, pk=pk)
    queryset = board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
    page = request.GET.get('page', 1)
    paginator = Paginator(queryset, 20)
    try:
        topics = paginator.page(page)
    except PageNotAnInteger:
        topics = paginator.page(1)
    except EmptyPage:
        topics = paginator.page(paginator.num_pages)
    return render(request, 'topics.html', {'board': board, 'topics': topics})
    

在 topics HTML列表的基础上,我们可以渲染分页组件:    
<!--templates/topics.html-->
{% if topics.has_other_pages %}
    <nav aria-label="Topics pagination" class="mb-4">
        <ul class="pagination">
            {% if topics.has_previous %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ topics.previous_page_number }}">Previous</a>
                </li>
            {% else %}
                <li class="page-item disabled">
                    <span class="page-link">Previous</span>
                </li>
            {% endif %}
            {% for page_num in topics.paginator.page_range %}
                {% if topics.number == page_num %}
                    <li class="page-item active">
                        <span class="page-link">
                            {{ page_num }}
                            <span class="sr-only">(current)</span>
                        </span>
                        </li>
                            {% else %}
                        <li class="page-item">
                        <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
                    </li>
                {% endif %}
            {% endfor %}
            {% if topics.has_next %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ topics.next_page_number }}">Next</a>
                </li>
            {% else %}
                <li class="page-item disabled">
                    <span class="page-link">Next</span>
                </li>
            {% endif %}
        </ul>
    </nav>
{% endif %}
#GCBV 分页
#下面,相同的实现,但这次使用ListView。
#boards/views.py
class TopicListView(ListView):
    model = Topic
    context_object_name = 'topics'
    template_name = 'topics.html'
    paginate_by = 20
    
    def get_context_data(self, **kwargs):
        kwargs['board'] = self.board
        return super().get_context_data(**kwargs)
    def get_queryset(self):
        self.board = get_object_or_404(Board, pk=self.kwargs.get('pk'))
        queryset = self.board.topics.order_by('-last_updated').annotate(replies=Count('posts') - 1)
        return queryset

        
#myproject/urls.py
url(r'^boards/(?P<pk>\d+)/$', views.TopicListView.as_view(), name='board_topics'),


#templates/topics.html
{% block content %}
    <div class="mb-4">
        <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
    </div>
    <table class="table mb-4">
        <!-- table content suppressed -->
    </table>
    {% if is_paginated %}
        <nav aria-label="Topics pagination" class="mb-4">
            <ul class="pagination">
                {% if page_obj.has_previous %}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
                    </li>
                {% else %}
                    <li class="page-item disabled">
                        <span class="page-link">Previous</span>
                    </li>
                {% endif %}
                {% for page_num in paginator.page_range %}
                    {% if page_obj.number == page_num %}
                        <li class="page-item active">
                            <span class="page-link">
                                {{ page_num }}
                                <span class="sr-only">(current)</span>
                            </span>
                        </li>
                    {% else %}
                        <li class="page-item">
                            <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
                        </li>
                    {% endif %}
                {% endfor %}
                {% if page_obj.has_next %}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
                    </li>
                {% else %}
                    <li class="page-item disabled">
                        <span class="page-link">Next</span>
                    </li>
                {% endif %}
            </ul>
        </nav>
    {% endif %}
{% endblock %}
#可复用的分页模板
#就像我们在 form.html 中封装模板时做的一样,我们也可以为分页的HTML代码片创建类似的东西。
#我们来对主题帖子页面进行分页,进而找到一种复用分页组件的方法法。
#boards/views.py
class PostListView(ListView):
    model = Post
    context_object_name = 'posts'
    template_name = 'topic_posts.html'
    paginate_by = 2
    def get_context_data(self, **kwargs):
        self.topic.views += 1
        self.topic.save()
        kwargs['topic'] = self.topic
        return super().get_context_data(**kwargs)
    def get_queryset(self):
        self.topic = get_object_or_404(Topic, board__pk=self.
        kwargs.get('pk'), pk=self.kwargs.get('topic_pk'))
        queryset = self.topic.posts.order_by('created_at')
        return queryset


#更新一下 url.py 
url(r'^boards/(?P<pk>\d+)/topics/(?P<topic_pk>\d+)/$', views.PostListView.as_view(), name='topic_posts'),


现在,我们从topics.html模板中获取分页部分的html代码片,
并在templates/includes 文件夹下面创建一个名为 pagination.html 的新文件,
和 forms.html 同级目录:
#templates/includes/pagination.html
{% if is_paginated %}
    <nav aria-label="Topics pagination" class="mb-4">
        <ul class="pagination">
            {% if page_obj.has_previous %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
                </li>
            {% else %}
                <li class="page-item disabled">
                    <span class="page-link">Previous</span>
                </li>
            {% endif %}
            {% for page_num in paginator.page_range %}
                {% if page_obj.number == page_num %}
                    <li class="page-item active">
                        <span class="page-link">
                            {{ page_num }}
                            <span class="sr-only">(current)</span>
                        </span>
                    </li>
                {% else %}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a>
                    </li>
                {% endif %}
            {% endfor %}
            {% if page_obj.has_next %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
                </li>
            {% else %}
                <li class="page-item disabled">
                    <span class="page-link">Next</span>
                </li>
            {% endif %}
        </ul>
    </nav>
{% endif %}


#现在,我们在 topic_posts.html 文件中来使用它:
#templates/topic_posts.html
{% block content %}
    <div class="mb-4">
        <a href="{% url 'reply_topic' topic.board.pk topic.pk %}"class="btn btn-primary" role="button">Reply</a>
    </div>
    {% for post in posts %}
        <div class="card {% if forloop.last %}mb-4{% else %}mb-2{% endif %} {% if forloop.first %}border-dark{% endif %}">
            {% if forloop.first %}
                <div class="card-header text-white bg-dark py-2 px-3">{{ topic.subject }}</div>
            {% endif %}
            <div class="card-body p-3">
                <div class="row">
                    <div class="col-2">
                        <img src="{% static 'img/avatar.svg' %}" alt="{{post.created_by.username }}" class="w-100">
                        <small>Posts: {{ post.created_by.posts.count }}</small>
                    </div>
                    <div class="col-10">
                        <div class="row mb-3">
                            <div class="col-6">
                                <strong class="text-muted">{{ post.created_by.username }}</strong>
                            </div>
                            <div class="col-6 text-right">
                                <small class="text-muted">{{ post.created_at}}</small>
                            </div>
                        </div>
                        {{ post.message }}
                        {% if post.created_by == user %}
                            <div class="mt-3">
                                <a href="{% url 'edit_post' post.topic.board.pk post.topic.pk post.pk %} "class="btn btn-primary btn-sm" role="button">Edit</a>
                            </div>
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>
    {% endfor %}
    {% include 'includes/pagination.html' %}
{% endblock %}
我们同样也可以更新一下先前的模板,topics.html 模板同样也可以这个封装的分页模板。
#templates/topics.html
{% block content %}
    <div class="mb-4">
        <a href="{% url 'new_topic' board.pk %}" class="btn btn-primary">New topic</a>
    </div>
    <table class="table mb-4">
        <!-- table code suppressed -->
    </table>
    {% include 'includes/pagination.html' %}
{% endblock %}

 

posted on 2018-09-06 16:10  larken  阅读(242)  评论(0编辑  收藏  举报