xiao987334176

一、概述

在之前的文章中,链接如下:https://www.cnblogs.com/xiao987334176/p/14313471.html

介绍了ElementUI 分页,前端请求一次接口,获取所有数据,由ElementUI 分页组件实现分页,也就是说由前端来完成了分页功能。

但是,在实际项目中,不可能一次性返回所有数据,比如几十万条数据。

 

比较理想的方案是,前端配合后端,一起来实现分页功能。大概思路如下:

1. 默认访问api,比如:http://127.0.0.1:8000/api/book/list/ ,接口返回10条数据。

2. 前端点击页码时,比如第二页,请求接口:http://127.0.0.1:8000/api/book/list/?page=2,这里的page=2,表示当前页码数,接口返回10条数据。

3. 后面的以此类推,总之,每点击一次,请求一次接口,返回10条数据。

 

效果如下:

 

二、前端代码

test.vue

<template>
  <div>
    <!-- 表格 -->
    <el-table :data="tableData.list" style="width: 100%">
      <el-table-column
        prop="id"
        label="编号"
        width="120">
      </el-table-column>           <!--设置列标-->
      <el-table-column
        prop="title"
        label="书名"
        width="120">
      </el-table-column>
      <el-table-column
        prop="price"
        label="价格"
        width="120">
      </el-table-column>
      <el-table-column
        prop="pub_date"
        label="出版日期"
        width="200">
      </el-table-column>
      <el-table-column
        prop="publish"
        label="出版社"
        width="120">
      </el-table-column>
    </el-table>
    <!-- 分页器 -->
    <div class="block" style="margin-top:15px;">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="[10, 15, 20, 25]"
        :page-size="pageSize"
        layout="total, prev, pager, next, jumper"
        :total="total">
      </el-pagination>
    </div>
  </div>
</template>

<script>
  import axios from \'axios\'

  export default {
    name: "test2",
    data() {
      return {
        tableData: {},
        currentPage: 1, // 当前页码
        total: 20, // 总条数
        pageSize: 2 // 每页的数据条数
      };
    },
    mounted() {
      this.getlivestockInfo(1);
    },
    methods: {
      //每页条数改变时触发 选择一页显示多少行
      handleSizeChange(val) {
        console.log(`每页 ${val} 条`);
        this.currentPage = 1;
        this.pageSize = val;
      },
      //当前页改变时触发 跳转其他页
      handleCurrentChange(val) {
        console.log(`当前页: ${val}`);
        this.currentPage = val;
        this.getlivestockInfo(val);
      },
      // 请求api,获取信息
      getlivestockInfo(num1) {
        var that = this;
        var params = new URLSearchParams();
        params.append(\'page\', num1);
        // console.log("params",params)
        let url = "http://127.0.0.1:8000/api/book/list/?page=" + that.currentPage
        axios.get(url, params)    //补上后台接口即可
          .then(response => {  // 请求成功
            // console.log(\'请求成功\');
            that.tableData = response.data.data;
            that.currentPage = num1;
            that.pageSize = that.tableData.pageSize;
            that.total = that.tableData.total;
            console.log(\'请求成功, 获取\' + that.tableData.list.length + "条数据");
          }).catch(error => {  // 请求失败
          console.log(\'请求失败\');
          console.log(error);
        })
      }
    }
  }
</script>

<style scoped>

</style>
View Code

 

代码解释:

<el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="[10, 15, 20, 25]"
        :page-size="pageSize"
        layout="total, prev, pager, next, jumper"
        :total="total">
      </el-pagination>

其中:
:current-page的值表示当前是第几页;
:page-sizes的值表示可以选择一页多少条;
:page-size的值表示当前一页显示几条;
layout的值表示分页需要显示的内容,例如“total” 表示总数、“next” 表示下一页等;
:total的值表示共几页;

因为currentPage、pageSize并不是具体的值,所以需要在script标签中的data()中为其进行赋值。于是在上面说到的slice大家都应该知道其作用了吧。在当所有的值都存在时,在界面上会自动把分的页显示出来,如效果图中的:1、2、3……6

 

其他代码就不做解释了,注释里面写的比较清楚。

 

三、后端代码

这里以django 3.1.5为后端

 

安装模块

pip3 install django-cors-headers djangorestframework

 

新建一个项目:paging_demo

 

修改paging_demo/settings.py

注册corsheaders和channels,corsheaders主要是用来解决跨域问题的。

INSTALLED_APPS = [
    \'django.contrib.admin\',
    \'django.contrib.auth\',
    \'django.contrib.contenttypes\',
    \'django.contrib.sessions\',
    \'django.contrib.messages\',
    \'django.contrib.staticfiles\',
    \'api.apps.ApiConfig\',
    \'corsheaders\',  # 注册应用cors
]

 

修改paging_demo/settings.py

注册中间件

MIDDLEWARE = [
    \'django.middleware.security.SecurityMiddleware\',
    \'django.contrib.sessions.middleware.SessionMiddleware\',
    \'django.middleware.common.CommonMiddleware\',
    \'django.middleware.csrf.CsrfViewMiddleware\',
    \'django.contrib.auth.middleware.AuthenticationMiddleware\',
    \'django.contrib.messages.middleware.MessageMiddleware\',
    \'django.middleware.clickjacking.XFrameOptionsMiddleware\',
    \'corsheaders.middleware.CorsMiddleware\',  # 注册组件cors
]

 

修改paging_demo/settings.py

最后一行增加以下内容

REST_FRAMEWORK = {
    \'DEFAULT_VERSIONING_CLASS\':"rest_framework.versioning.URLPathVersioning",
    \'DEFAULT_VERSION\': \'v1\',
    \'ALLOWED_VERSIONS\': [\'v1\', \'v2\'],
    \'VERSION_PARAM\': \'version\',
    \'DEFAULT_PAGINATION_CLASS\': \'rest_framework.pagination.PageNumberPagination\',
    \'PAGE_SIZE\':2  # 默认分页大小
}

#跨域增加忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
# CORS_ORIGIN_WHITELIST = (
#     \'*\'
# )

CORS_ALLOW_METHODS = (
    \'DELETE\',
    \'GET\',
    \'OPTIONS\',
    \'PATCH\',
    \'POST\',
    \'PUT\',
    \'VIEW\',
)

CORS_ALLOW_HEADERS = (
    \'XMLHttpRequest\',
    \'X_FILENAME\',
    \'accept-encoding\',
    \'authorization\',
    \'content-type\',
    \'dnt\',
    \'origin\',
    \'user-agent\',
    \'x-csrftoken\',
    \'x-requested-with\',
    \'Pragma\',
)
View Code

注意:PAGE_SIZE 根据实际情况修改

 

修改paging_demo/urls.py

增加路由

from django.contrib import admin
from django.urls import path
from api import views

urlpatterns = [
    path(\'admin/\', admin.site.urls),
    path(\'api/book/list/\', views.BookView.as_view({\'get\':\'list\'}),name=\'books_list\'),
]

 

修改api/views.py

from django.shortcuts import render
from rest_framework.views import APIView
import json
from rest_framework.viewsets import ViewSetMixin
from django.shortcuts import render, HttpResponse
from rest_framework.response import Response
from rest_framework import status
from django.http import JsonResponse
from api import models
from api.serializers.book import BookSerializer
from rest_framework.pagination import PageNumberPagination
from django.db import transaction
from paging_demo import settings

# 书籍
class BookView(ViewSetMixin, APIView):
    """书籍"""
    # 查看书籍列表
    def list(self, request, *args, **kwargs):
        queryset = models.Book.objects.all()
        serializer_class = BookSerializer
        # 排序
        queryset = queryset.order_by(\'id\')
        # 分页
        page = PageNumberPagination()
        course_list = page.paginate_queryset(queryset, self.request, self)
        # 分页之后的结果执行序列化
        ser = serializer_class(instance=course_list, many=True)
        data = ser.data
        # print("data",data)
        if not data:
            return JsonResponse({\'status\': status.HTTP_501_NOT_IMPLEMENTED, \'data\': data, \'msg\': \'数据为空\'},
                                status=status.HTTP_501_NOT_IMPLEMENTED)
        
        # 封装返回数据格式
        data = {
            \'list\':data,
            \'pageSize\': settings.REST_FRAMEWORK[\'PAGE_SIZE\'],
            \'total\':queryset.count()
        }

        return JsonResponse({\'status\': status.HTTP_200_OK, \'data\': data},
                            status=status.HTTP_200_OK)
View Code

 

修改api/models.py

from django.db import models

# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=32, unique=True,verbose_name="名称")
    price = models.DecimalField(max_digits=8, decimal_places=2,verbose_name="价格")
    pub_date = models.DateField(verbose_name="出版日期")
    publish = models.CharField(max_length=32, verbose_name="出版社")
View Code

 

在api目录下,创建文件夹serializers,并在此文件下创建book.py

# !/usr/bin/python3
# -*- coding: utf-8 -*-
from rest_framework import serializers
from api import models


class BookSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Book
        fields = \'__all__\'

 

生成数据库,使用以下命令:

python manage.py makemigrations
python manage.py migrate

 

默认使用的是sqlite3数据库,使用Navicat软件打开数据库,使用以下命令插入数据:

INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (1, \'python 高级开发实战\', 98.63, \'2020-05-06\', \'工业出版社\', 1);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (2, \'python 开发实战\', 97.5, \'2020-05-05\', \'工业出版社\', 2);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (3, \'活着\', 56, \'2020-06-01\', \'工业出版社\', 3);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (4, \'兄弟\', 47, \'2020-06-02\', \'工业出版社\', 4);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (5, \'进化心理学\', 52, \'2020-06-03\', \'工业出版社\', 5);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (6, \'包法利夫人\', 39, \'2020-06-04\', \'工业出版社\', 6);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (7, \'谈美\', 46, \'2020-06-05\', \'工业出版社\', 7);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (8, \'局外人\', 43, \'2020-06-05\', \'工业出版社\', 8);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (9, \'傲慢与偏见\', 58, \'2020-06-07\', \'工业出版社\', 9);
INSERT INTO "main"."api_book" ("id", "title", "price", "pub_date", "publish", "ROWID") VALUES (10, \'变形记\', 36, \'2020-06-08\', \'工业出版社\', 10);
View Code

 

启动django项目即可

 

最后,访问vue页面,效果就是本文开始的动态图。

 

这里说明一下接口调用问题,由于django rest framework使用PageNumberPagination进行分页,它必须是get请求才行。如果使用post,需要修改源码才行。

前端调用接口,比如:http://127.0.0.1:8000/api/book/list/?page=2。注意:由于PageNumberPagination默认接收分页参数为page,因此前端这里必须是page。

如果不是page,需要对PageNumberPagination进行手动封装才行。

 

 

本文参考链接:

https://blog.csdn.net/weixin_46214344/article/details/104051480

分类:

技术点:

相关文章: