ElementUI 分页+django rest framework
一、概述
在之前的文章中,链接如下: 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>
<!-- 表格 -->
<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>
</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>
代码解释:
<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
其他代码就不做解释了,注释里面写的比较清楚。
注意:确保已经安装了ElementUI和axios,根据实际情况配置路由。
三、后端代码
这里以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
]
注册中间件
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
]
最后一行增加以下内容
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',
)
注意: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)
修改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="出版社")
在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);