如何使用Django REST框架和Vue进行自定义分页

247 阅读4分钟

使用Django REST框架与Vue进行自定义分页

当在网页上显示大型项目时,人们需要对应用内容进行分割。我们可以用Django来实现这一点,因为它有一个预建的类--分页器,可以创建和管理应用程序的分页数据。

本文将介绍我们如何使用Django REST框架和Vue来定制和修改分页样式。

最后,读者将了解数据分页的各种方式以及它在Web开发中的重要性。

前提条件

要从本教程中获得最大的收获,你应该具备以下条件。

  • 对Python和Django概念的了解。
  • 对Django REST框架和Vue有充分的了解。
  • 安装一个合适的IDE,如Pycharm、Visual Studio Code等。

本文将使用Pycharm IDE。

分页

分页是将网页内容分割成不连续的页面的过程,以便在处理大型项目列表时更有效地使用和阅读。

Django有一个预置的类,Paginator ,用于创建分页,并使用默认样式管理分页的项目。

分页可以通过Class-Based ViewsFunction-Based Views 来完成。有时,人们可以使用Django REST Framework 来定制和修改分页格式,正如本教程中讨论的那样。

分割网页数据有其优点。

  • 增加了内容的可读性,因为它们不那么拥挤。
  • 减少服务器的负荷,因为更容易从服务器上获得一部分数据。
  • 增加每个用户的页面浏览量和网站的总页面浏览量,最大限度地增加他们可以提供的印象数和网站可以销售的广告单位数。

分页的方式

一个通用的ListView ,在Django中是一个基于类的视图,而不是使用其他东西,比如基于函数的视图。

所以在这篇文章中,我们采取的方法是向你展示如何从一个基于类的通用ListView ,创建一个列表视图。

项目结构。

现在,让我们来构建我们的项目,建立一个博客网站,用于发布项目,然后对其进行分页。

检查Django的版本,如果还没有安装,请安装。

pip install django

接下来,通过运行以下命令创建Django项目。

django-admin startproject blogsite

继续并在同一目录下创建blog 应用程序,如下图所示。

python manage.py startapp blog

下面是项目的结构。

└── blogsite         # < project root package
    ├── blog             # < blog app
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   ├── models.py
    │   ├── urls.py
    │   └── views.py
    ├── manage.py  
    ├── templates   # < templates folder
    └── blogsite    
        ├── settings.py # Django settings file
        ├── urls.py
        └── wsgi.py

成功创建Django项目后,在终端和cd 到工作目录,并通过运行以下命令启动Django开发服务器。

python manage.py runserver

输出。Django Output

基于类的视图

我们可以使用基于类的视图来编写我们的API视图,而不是基于函数的视图。正如我们将看到的,这是一个强大的模式,它允许我们在我们的应用程序上重复使用普通功能,并帮助我们保持我们的代码DRY

为了创建这个视图,在views.py 文件中添加以下内容。

from django.shortcuts import render
from django.views import generic
from .models import Post

class PostList(generic.ListView):
    queryset = Post.objects.filter(status=1).order_by('-created_on')
    template_name = 'index.html'

class PostDetail(generic.DetailView):
    model = Post
    template_name = 'post_detail.html'

然后我们将在PostList 视图下引入一个新的属性paginate_by ,以指定每页要显示的博客项目的数量。

class PostList(generic.ListView):
    queryset = Post.objects.filter(status=1).order_by('-created_on')
    template_name = 'index.html'
    paginate_by = 3

为了在屏幕上显示分页内容,我们将使用模板文件夹中的index.html 文件。该文件内容如下。

{% extends "base.html" %}
{% block content %}
<style>
    body {
        font-family: "Roboto", sans-serif;
        font-size: 18px;
        background-color: #fdfdfd;
    }

    .head_text {
        color: white;
    }

    .card {
        box-shadow: 0 16px 48px #E3E7EB;
    }
</style>

<header class="masthead">
    <div class="overlay"></div>
    <div class="container">
        <div class="row">
            <div class=" col-md-8 col-md-10 mx-auto">
                <div class="site-heading">
                    <h3 class=" site-heading my-4 mt-3 text-white"> Welcome to my awesome Blog </h3>
                    <p class="text-light">We Love Django As much as you do..! &nbsp
                    </p>
                </div>
            </div>
        </div>
    </div>
</header>
<div class="container">
    <div class="row">
        <!-- Blog Entries Column -->
        <div class="col-md-8 mt-3 left">
            {% for post in post_list %}
            <div class="card mb-4">
                <div class="card-body">
                    <h2 class="card-title">{{ post.title }}</h2>
                    <p class="card-text text-muted h6">{{ post.author }} | {{ post.created_on}} </p>
                    <p class="card-text">{{post.content|slice:":200" }}</p>
                    <a href="{% url 'post_detail' post.slug  %}" class="btn btn-primary">Read More &rarr;</a>
                </div>
            </div>
            {% endfor %}
        </div>
        {% block sidebar %} {% include 'sidebar.html' %} {% endblock sidebar %}
    </div>
</div>
{%endblock%}

上面的代码片断使用带有内联CSS样式的模板标签向用户显示数据库的行内容。{% extends% } 标签指示Django从base.html 文件中继承。然后我们使用{% block content %} 标签将我们的内容注入到其他HTML文件中。

for loop 遍历我们的post 模型中的各个字段。然后使用模型和字段名从数据库中获取这些字段。例如,post.author ,获取文章的作者姓名并显示在屏幕上。

现在,继续并重新启动你的服务器。你应该能在视图上看到以下内容。Class Based Views

基于函数的视图

基于函数的视图是Django中由函数定义的视图。使用函数,我们可以使用Django中的某些函数来创建视图,如HttpResponse() (将HTML硬编码到视图中)或render() ,将模板文件渲染到视图中。

现在继续,打开views.py ,添加以下代码片段。

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage

# Create your views here.
def PostList(request):
    object_list = Post.objects.filter(status=1).order_by('-created_on')
    paginator = Paginator(object_list, 3)  # 3 posts in each page
    page = request.GET.get('page')
    try:
        post_list = paginator.page(page)
    except PageNotAnInteger:
           
        post_list = paginator.page(1)
    except EmptyPage:
        
        post_list = paginator.page(paginator.num_pages)
    return render(request,
                  'index.html',
                  {'page': page,
                   'post_list': post_list})

在上面的视图中,我们已经实例化了Paginator 类,每个页面上要显示的对象数量(三个)。

request.GET.get('page') 参数返回当前的页面编号。我们使用了page() 方法来获取相应页码的项目。

然后,我们对PageNotAnIntegerEmptyPage 有两个异常声明,都是InvalidPage 的子类,然后,最后渲染HTML内容。

在你的index.html ,将下面的代码粘贴在片段的下面。

{% if post_list.has_other_pages %}
  <nav aria-label="Page navigation conatiner"></nav>
  <ul class="pagination justify-content-center">
    {% if post_list.has_previous %}
    <li><a href="?page={{ post_list.previous_page_number }}" class="page-link">&laquo; PREV </a></li>
    {% endif %}
    {% if post_list.has_next %}
    <li><a href="?page={{ post_list.next_page_number }}" class="page-link"> NEXT &raquo;</a></li>
   {% endif %}
  </ul>
  </nav>
</div>
{% endif %}

现在继续并重新启动你的服务器;你应该能够看到以下内容的显示。Function Based Views

使用Django Rest框架进行自定义分页

对于我们之前讨论过的自定义分页,我们用以下命令安装Django REST框架和Vue。

pip install djangorestframework
npm install vue

然后按照前面的步骤创建一个Djangopagination 项目。项目的结构如下所示。

└── pagination         # < project root package
    ├── pagination            # < todo app
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   ├── models.py
    │   ├── serializers.py
    │   ├── urls.py
    │   └── views.py
    ├── manage.py  
    ├── templates/blog
    └── pagination   
        ├── settings.py # Django settings file
        ├── urls.py
        └── wsgi.py

打开settings.py ,添加以下内容。

INSTALLED_APPS = [
    'rest_framework',
    'blog.apps.BlogConfig',
]

现在,继续并在models.py 文件中创建Post 模型,添加以下代码片段。

from django.db import models
from django.contrib.auth.models import User

STATUS = (
    (0, "Draft"),
    (1, "Publish")
)


class Post(models.Model):
    title = models.CharField(max_length=200, unique=True)
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
    updated_on = models.DateTimeField(auto_now=True)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)

    class Meta:
        ordering = ['-created_on']

    def __str__(self):
        return self.title

views.py ,使用page_size 变量和分页类指定每页显示的帖子数量。

from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
from .models import Post
from .serializers import PostSerializer
# Create your views here.
def index(request):
    return render(request, 'blog/index.html')

# Create Pagination class how many post
class PostPagination(PageNumberPagination):
    page_size = 3

class PostViewSet(viewsets.ModelViewSet):
    pagination_class = PostPagination
    serializer_class = PostSerializer
    queryset = Post.objects.all()

将下面的代码添加到urls.py ,并将视图和模型链接到URL上。

from django.urls import path,include
from rest_framework.routers import DefaultRouter
from . import  views

router = DefaultRouter()
router.register("posts",views.PostViewSet, basename="posts")
urlpatterns = [
    path('',views.index, name='index'),
    path('',include(router.urls))
]

对于REST API,导入serializersPost 模型,然后在serializers.py 中添加以下代码,指定所有要从数据库中获得的字段。

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ('id', 'title', 'slug', 'author', 'updated_on', 'content', 'created_on', 'status',)

使用models.py ,通过制作和迁移所有的迁移来更新数据库。

python manage.py makemigrations
python manage.py migrate.

成功迁移数据库后,使用下面的命令运行应用程序。

python manage.py runserver

输出。Post List

为了在主页上显示帖子内容,我们将使用Vue.js来渲染静态文件。在博客应用内创建的templates 文件夹下,将下面的代码添加到index.html 文件中。

<!DOCTYPE html>
<html>
    <body>
        <div id="blog">
            <div
                v-for="post in posts"
                v-bind:key="post.id"
            >
                <h2>[[ post.title]]</h2>
                <p>[[ post.updated_on]]</p>
                <p>[[ post.User]]</p>
                <p>[[ post.content]]</p>
            </div>

            <template v-if="showPrevButton">
                <button @click="loadPrev()">Prev</button>
            </template>

            <template v-if="showNextButton">
                <button @click="loadNext()">Next</button>
            </template>
        </div>

        <script src="https://unpkg.com/vue@next"></script>
        <script>
            const Blog = {
                data() {
                    return {
                        posts: [],
                        currentPage: 1,
                        showNextButton: false,
                        showPrevButton: false
                    }
                },
                delimiters: ['[[', ']]'],
                mounted() {
                    this.getPosts()
                },
                methods: {
                    loadNext() {
                        this.currentPage += 1
                        this.getPosts()
                    },
                    loadPrev() {
                        this.currentPage -= 1
                        this.getPosts()
                    },
                    getPosts() {
                        fetch(`/posts/?page=${this.currentPage}`)
                            .then(response => {
                                return response.json()
                            })
                            .then(data => {
                                console.log(data)

                                this.showNextButton = false
                                this.showPrevButton = false

                                if (data.next) {
                                    this.showNextButton = true
                                }

                                if (data.previous) {
                                    this.showPrevButton = true
                                }

                                this.posts = data.results
                            })
                            .catch(error => {
                                console.log(error)
                            })
                    }
                }
            }

            Vue.createApp(Blog).mount('#blog')
        </script>
    </body>
</html>

我们使用之前从上面的代码中创建的post 模型来获取数据库字段。然后我们使用Vue.js来渲染内容,这取决于当前页面或下一个/前一个页面。

现在继续并重启你的服务器。预期的输出如下所示。

Custom Pagination

总结

本教程已经带你了解了使用Django框架和Vue.js的分页的基本概念。我们已经看到了这个功能是如何帮助在网页上呈现出良好的结构化输出的。