django之ajax

news2024/12/23 10:28:23

【一】前言

  • Ajax
    • 异步提交
    • 局部刷新

发送请求的方式

  • 浏览器地址栏直接输入url回车 GET请求
  • a标签href属性 GET请求
  • form表单 GET请求/POST请求
  • ajax GET请求/POST请求

​ AJAX 不是新的编程语言, 而是一种使用先有标准的新方法(比如装饰器)

​ ajax 最大的优点是在不重新加载整个页面的情况下, 可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程。)

ajax不需要任何浏览器插件,但是需要用户允许JavaScript在浏览器上执行。

  • 同步交互:客户端发出一个请求后, 需要等待服务器响应结束后,才能发出第二个请求。
  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

​ ajax除了异步的特点之外,还有就是:浏览器页面局部刷新(就是给用户的感受是在不知不觉中完成请求和响应过程)

【二】Ajax案例

  • 页面上有三个 input 框
    • 在前面两个框输入数字,点击按钮,朝后端发送Ajax请求
    • 在后端计算出结果,再返回给前端动态展示的第三个input框中
  • 要求
    • 整个过程页面不能刷新,也不许在前端计算

urlencoded

form formdata

json数据格式

【二】基本语法

(1)前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% load static %}
    <title>Title</title>
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>

<input type="text" id="d1">
<input type="text" id="d2">
<input type="text" id="d3">
<p>
<button id="btn_result">点我计算结果</button>
</p>

<script>
    $(document).ready(function(){
        // 给按钮绑定点击事件
        $('#btn_result').click(function () {
            // 发送ajax请求
            $.ajax({
                // 指定后端URL
                url: '',  // 替换成你的后端URL
                // 请求方式
                type: 'post',
                // 数据
                data: {
                    'username': 'jason',
                    'password': 123
                },
                // 成功回调函数
                success: function (data) {
                    alert(data.message);  // 在页面上弹出返回的数据
                }
            });
        });
    });
</script>

</body>
</html>

(2)后端(字符串)

  • 直接返回字符串结果
# urls.py
from django.contrib import admin
from django.urls import path, re_path, include
from apply01 import views

urlpatterns = [
    re_path(r'^ab_ajax/', views.ab_ajax, name='ab_ajax')
]

# views.py
from django.shortcuts import render, HttpResponse

def ab_ajax(request):
    if request.method == "POST":
        print(request.POST)

    return render(request, "index.html")

(3)Ajax 语法

<script>
    // 等待页面元素加载完毕。
    // 注意:$(document).ready() 与 window.onload 类似,都是页面加载完毕时触发的事件。
    $(document).ready(
        // 给按钮点击绑定事件
        // 注意:$("#btn_result") 表示获取 id 为 btn_result 的元素。
        $("#btn_result").click(function () {
            let numberOne = $("#numberOne").val();
            let numberTwo = $("#numberTwo").val();
            let result = $("#numberResult")
            // $.ajax为固定用法,表示启用ajax
            $.ajax(
                {
                    //url后面跟的是你这个ajax提交数据的路径,向谁提交,不写就是向当前路径提交
                    url: "",
                    //type为标定你这个ajax请求的方法
                    type: "post",
                    //data后面跟的就是你提交给后端的数据
                    data: {numberOne: numberOne, numberTwo: numberTwo},
                    //success为回调函数,参数data即后端给你返回的数据
                    success: function (data) {
                        // 注意:data 表示返回的数据。
                        console.log(data)
                        //  注意:result.val(data) 表示将返回的数据赋值给 id 为 result 的元素的 value 属性。
                        result.val(data)
                    }
                }
            )
        })
    )
</script>
  • 针对后端如果是用HttpResponse返回的数据,回调函数不会自动帮你返回反序列化。
  • 如果后端直接用的是JsonResponse返回的数据,回调函数会自动帮你反序列化。

【三】普通版

(1)前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>
<body>
<div>number1 : <input type="text" id="numberOne"></div>
<div>number2 : <input type="text" id="numberTwo"></div>
<div>result : <input type="text" id="numberResult"></div>

<button id="btn_result">点我计算结果</button>
<script>
    // 等待页面元素加载完毕。
    // 注意:$(document).ready() 与 window.onload 类似,都是页面加载完毕时触发的事件。
    $(document).ready(
        // 给按钮点击绑定事件
        // 注意:$("#btn_result") 表示获取 id 为 btn_result 的元素。
        $("#btn_result").click(function () {
            let numberOne = $("#numberOne").val();
            let numberTwo = $("#numberTwo").val();
            let result = $("#numberResult")
            // $.ajax为固定用法,表示启用ajax
            $.ajax(
                {
                    //url后面跟的是你这个ajax提交数据的路径,向谁提交,不写就是向当前路径提交
                    url: "",
                    //type为标定你这个ajax请求的方法
                    type: "post",
                    //data后面跟的就是你提交给后端的数据
                    data: {numberOne: numberOne, numberTwo: numberTwo},
                    //success为回调函数,参数data即后端给你返回的数据
                    success: function (data) {
                        // 注意:data 表示返回的数据。
                        console.log(data)
                        //  注意:result.val(data) 表示将返回的数据赋值给 id 为 result 的元素的 value 属性。
                        result.val(data)
                    }
                }
            )
        })
    )
</script>
</body>
</html>

(2)后端(字符串)

  • 直接返回字符串结果
from django.shortcuts import render, HttpResponse


# Create your views here.
def add_number(request):
    if request.method == "POST":
        data = request.POST
        #  获取前端传递的参数
        # <QueryDict: {'numberOne': ['1'], 'numberTwo': ['2']}>
        number_one = data.get("numberOne")
        number_two = data.get("numberTwo")
        # 计算结果 : 注意从前端取出来的数字是字符串类型,需要做类型转换才能运算
        result = int(number_one) + int(number_two)
        # 返回响应数据
        return HttpResponse(result)
    return render(request, "index.html")

(3)Ajax 语法

<script>
    // 等待页面元素加载完毕。
    // 注意:$(document).ready() 与 window.onload 类似,都是页面加载完毕时触发的事件。
    $(document).ready(
        // 给按钮点击绑定事件
        // 注意:$("#btn_result") 表示获取 id 为 btn_result 的元素。
        $("#btn_result").click(function () {
            let numberOne = $("#numberOne").val();
            let numberTwo = $("#numberTwo").val();
            let result = $("#numberResult")
            // $.ajax为固定用法,表示启用ajax
            $.ajax(
                {
                    //url后面跟的是你这个ajax提交数据的路径,向谁提交,不写就是向当前路径提交
                    url: "",
                    //type为标定你这个ajax请求的方法
                    type: "post",
                    //data后面跟的就是你提交给后端的数据
                    data: {numberOne: numberOne, numberTwo: numberTwo},
                    //success为回调函数,参数data即后端给你返回的数据
                    success: function (data) {
                        // 注意:data 表示返回的数据。
                        console.log(data)
                        //  注意:result.val(data) 表示将返回的数据赋值给 id 为 result 的元素的 value 属性。
                        result.val(data)
                    }
                }
            )
        })
    )
</script>

【四】升级版(json模块)

  • 后端返回的是字典格式(JSON)的数据
  • json模块序列化
from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
import json


# Create your views here.
def ab_ajax(request):
    if request.method == 'POST':
        # print(request.POST)  # <QueryDict: {'i1': ['3'], 'i2': ['4']}>
        num1 = request.POST.get('i1')  # 3 - 文本类型
        num2 = request.POST.get('i2')  # 4 - 文本类型
        # 强转类型并做运算
        sum = int(num1) + int(num2)
        # 返回数据
        data = {
            "message": "success",
            "sum": sum,
        }
        # 需要将数据序列化进行传输
        return HttpResponse(json.dumps(data))
    return render(request, 'ab_ajax.html')

(1)前端

  • 新增Ajax中的参数 dataType,指定返回的参数自动被序列化后的格式
<script>
    // 等待页面元素加载完毕。
    // 注意:$(document).ready() 与 window.onload 类似,都是页面加载完毕时触发的事件。
    $(document).ready(
        // 给按钮点击绑定事件
        // 注意:$("#btn_result") 表示获取 id 为 btn_result 的元素。
        $("#btn_result").click(function () {
            let numberOne = $("#numberOne").val();
            let numberTwo = $("#numberTwo").val();
            let result = $("#numberResult")
            $.ajax(
                {
                    url: "",
                    type: "post",
                    data: {numberOne: numberOne, numberTwo: numberTwo},
                    // 前端反序列化数据 方式一
                    // 在Ajax上加参数
                    // dataType 参数应该是一个字符串,表示期望从服务器返回的数据类型(如 "json", "xml", "script", "html" 等)
                    dataType: "json",
                    success: function (data) {
                        // 注意:data 表示返回的数据。
                        console.log(data) // {message: 'success', result: 4}
                        //  注意:result.val(data) 表示将返回的数据赋值给 id 为 result 的元素的 value 属性。
                        result.val(data.result)
                    }
                }
            )
        })
    )
</script>

(2)后端

from django.shortcuts import render, HttpResponse
import json


# Create your views here.
def add_number(request):
    if request.method == "POST":
        data = request.POST
        #  获取前端传递的参数
        # <QueryDict: {'numberOne': ['1'], 'numberTwo': ['2']}>
        number_one = data.get("numberOne")
        number_two = data.get("numberTwo")
        # 计算结果 : 注意从前端取出来的数字是字符串类型,需要做类型转换才能运算
        result = int(number_one) + int(number_two)
        result = {
            "message": "success",
            "result": result
        }
        # 返回响应数据 - 使用json模块序列化成json字符串
        return HttpResponse(json.dumps(result))
    return render(request, "index.html")

【五】进阶版(JsonResponse)

from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
import json


# Create your views here.

def add_number(request):
    if request.method == "POST":
        data = request.POST
        #  获取前端传递的参数
        # <QueryDict: {'numberOne': ['1'], 'numberTwo': ['2']}>
        number_one = data.get("numberOne")
        number_two = data.get("numberTwo")
        # 计算结果 : 注意从前端取出来的数字是字符串类型,需要做类型转换才能运算
        result = int(number_one) + int(number_two)
        result = {
            "message": "success",
            "result": result
        }
        # 返回响应数据 - 使用JsonResponse对象序列化成json字符串
        return JsonResponse(result)
    return render(request, "index.html")

小结

【1】普通版:
这个版本的代码使用了Django框架来实现前后端交互。前端代码使用了jQuery库,并通过Ajax发送POST请求来传递两个数给后端。后端接收到请求后,从POST数据中获取两个数并进行求和,然后将结果作为字符串返回给前端。

【2】升级版(json模块):
这个版本的代码在普通版的基础上进行了升级。后端返回的是一个字典格式的JSON数据,使用了Django的JsonResponse对象来进行序列化。前端通过设置dataType: "json"参数来指定返回数据的自动序列化格式。

【3】进阶版(JsonResponse):
这个版本的代码与升级版类似,后端使用了JsonResponse对象来返回计算结果。这个版本的代码是最终版本,使用JsonResponse可以更方便地返回JSON格式的数据。

Ajax发送JSON格式数据

  • 前后端传输数据的时候一定要保证编码格式数据与真正的数据格式是一致的

【1】引入

(1)后端

def ab_json(request):
    if request.method == 'POST':
        print(request.POST) #<QueryDict: {}>
    return render(request, 'ab_json.html')

(2)前端

<button class="btn btn-danger" id="d1">点我</button>

<script>
    $('#d1').click(function () {
        $.ajax({
            url: '',
            type: 'post',
            // 前端数据转JSON格式数据 :JSON.stringify
            data: JSON.stringify({"username": "dream", "password": 521521}),
            // 不指定参数,默认就是 urlencoded
            contentType: 'application/json',
            success: function (args) {

            }
        })
    })
</script>
  • 请求标头携带的数据格式
    • 已成功转换为JSON格式
{"username":"dream","password":521521}

【2】后端

  • 接收到的数据为空
def ab_json(request):
    if request.method == 'POST':
        print(request.POST) #<QueryDict: {}>
    return render(request, 'ab_json.html')
  • Django针对JSON格式的数据不会做任何处理
  • 针对JSON格式的数据需要自己手动处理
  • 解决办法
def ab_json(request):
    print(request.is_ajax())  # True
    if request.method == 'POST':
        print(request.POST)  # <QueryDict: {}>

    print(request.body)  # 返回的是二进制数据 :b'{"username":"dream","password":521521}'
    # 针对JSON格式的数据需要自己手动处理
    json_bytes = request.body

    # (1)方式一:先解码 再转换数据格式
    json_str = json_bytes.decode('utf-8')
    json_dict = json.loads(json_str)
    print(json_dict, type(json_dict))  # {'username': 'dream', 'password': 521521} <class 'dict'>

    # (2)方式二:json.loads(二进制数据) 内部可以自动解码再反序列化
    json_dict_loads = json.loads(json_bytes)
    print(json_dict_loads, type(json_dict_loads))  # {'username': 'dream', 'password': 521521} <class 'dict'>


    return render(request, 'ab_json.html')

【3】总结

(1)注意参数

  • 前端在通过Ajax请求发送数据的时候,一定要注参数修改
// 不指定参数,默认就是 urlencoded
contentType: 'application/json',

(2)符合JSON数据格式

  • 数据是真正的JSON格式数据
发送的数据一定要符合JSON格式
或经过JSON序列化再传输

(3)手动处理前端传入的JSON数据

  • Django后端不会帮我们处理JSON格式数据,需要自己手动处理request.body中的数据
通过Ajax传过来的数据是二进制数据
在request.body中
要经过自己的反序列化才能拿到我们想要的数据

【三】Ajax发送文件数据

【1】发送方法(formdata对象)

  • Ajax发送文件数据需要借助js内置对象formdata

(1)前端

<p>username: <input type="text" name="username" id="d1"></p>
<p>password: <input type="password" name="password" id="d2"></p>
<p>file: <input type="file" id="d3"></p>

<button id="btn" class="btn btn-danger">提交</button>


<script>
    // 点击按钮向后端发送普通键值对数据和文件数据
    $("#btn").on('click', function () {
        // (1)先生成一个内置对象
        let formDataObj = new FormData();

        // (2)支持添加普通的键值对
        formDataObj.append('username', $("#d1").val());
        formDataObj.append('password', $("#d2").val());

        // (3)支持添加文件对象 ---> 先拿到标签对象 ----> 再拿到文件对象
        formDataObj.append('myfile', $("#d3")[0].files[0]);

        // (4)基于Ajax,将文件对象发送给后端
        $.ajax({
            url: '',
            type: 'post',
            // 直接将对象放到data里面即可
            data: formDataObj,

            // Ajax发送文件必须添加的两个参数
            // 不需要使用任何编码 -  Django后端能自动识别 formdata 对象
            contentType: false,
            // 告诉浏览器不要对我的数据进行任何处理
            processData: false,

            success: function (args) {

            }
        })
    })
</script>

(2)后端

def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print('POST::>>', request.POST)
            # 普通键值对放在了  request.POST   中
            # POST::>> <QueryDict: {'username': ['dream'], 'password': ['666']}>
            print('FILES::>>', request.FILES)
            # 文件数据放在了  request.FILES   中
            # FILES::>> <MultiValueDict: {'myfile': [<InMemoryUploadedFile: img.png (image/png)>]}>

    return render(request, 'ab_file.html')

【2】发送文件数据的格式

// 点击按钮向后端发送普通键值对数据和文件数据
$("#btn").on('click', function () {
    // (1)先生成一个内置对象
    let formDataObj = new FormData();

    // (2)支持添加普通的键值对
    formDataObj.append('username', $("#d1").val());
    formDataObj.append('password', $("#d2").val());

    // (3)支持添加文件对象 ---> 先拿到标签对象 ----> 再拿到文件对象
    formDataObj.append('myfile', $("#d3")[0].files[0]);

    // (4)基于Ajax,将文件对象发送给后端
    $.ajax({
    url: '',
    type: 'post',
    // 直接将对象放到data里面即可
    data: formDataObj,

    // Ajax发送文件必须添加的两个参数
    // 不需要使用任何编码 -  Django后端能自动识别 formdata 对象
    contentType: false,
    // 告诉浏览器不要对我的数据进行任何处理
    processData: false,

    success: function (args) {

    }
})

【3】小结

(1)借助FormData对象

  • Ajax发送文件数据需要利用内置对象FormData
// (1)先生成一个内置对象
let formDataObj = new FormData();

// (2)支持添加普通的键值对
formDataObj.append('username', $("#d1").val());
formDataObj.append('password', $("#d2").val());

// (3)支持添加文件对象 ---> 先拿到标签对象 ----> 再拿到文件对象
formDataObj.append('myfile', $("#d3")[0].files[0]);

(2)必须携带两个参数

  • 需要指定两个关键性的参数
// Ajax发送文件必须添加的两个参数
// 不需要使用任何编码 -  Django后端能自动识别 formdata 对象
contentType: false,
// 告诉浏览器不要对我的数据进行任何处理
processData: false,

(3)后端解析数据

  • Django后端能直接自动识别到

    FormData
    

    对象

    • 将内部的普通键值对自动解析并封装到request.POST
    • 将内部的文件数据自动解析并封装到request.FILES
print('POST::>>', request.POST)
# 普通键值对放在了  request.POST   中
# POST::>> <QueryDict: {'username': ['dream'], 'password': ['666']}>

print('FILES::>>', request.FILES)
# 文件数据放在了  request.FILES   中
# FILES::>> <MultiValueDict: {'myfile': [<InMemoryUploadedFile: img.png (image/png)>]}>

总结:

  • 1.需要利用内置对象FormData

    2.添加普通的键值对

    formDataObj.append('username', $("#d1").val());
    formDataObj.append('password', $("#d2").val());
    

    3.添加文件对象

  • formDataObj.append('myfile', $("#d3")[0].files[0]);
    
  • 需要指定两个关键性的参数

  •   contentType: false,
                // 告诉浏览器不要对我的数据进行任何处理
      processData: false,
    
  • django后端能够直接识别到formdata对象能够将内部的普通键值自动解析并封装到request.POST中 文件数据能够自动解析并封装到request.FILES中。

批量插入数据

先导包

<!—— 在head标签当中 -->   
{% load static %}
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
# urls.py
from django.urls import path, re_path, include
from apply01 import views

urlpatterns = [
	# 插入数据
    re_path(r'^ab_pl/', views.ab_pl, name='ab_pl')
]

【1】第一种

# views.py
from django.db import models
from apply02 import models
from django.shortcuts import render, HttpResponse, redirect,reverse
def ab_pl(request):
    # (1)先给Book表插入一万条数据
    for i in range(1000):
        models.Book.objects.create(title=f'第{i}本书')
    # (2)将所有数据查询到并展示给前端页面
    res_books = models.Book.objects.all()
    # (3)将查询出来的数据传递给html页面
    return render(request, 'books.html', locals())

【2】第二种

  • 当你想要批量插入数据的时候,使用orm给你提供的bulk_create能够大大的减少操作时间

    book_list = []
    for i in range(100):
        book = models.Book.objects.create(title=f'第{i}本书')
        book_list.append(book)
    models.Book.objects.bulk_create(book_list)
    return render(request, 'books.html', locals())
<!-- 前端books.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for book in res_books %}
    <p>{{ book.title }}</p>
{% endfor %}
</body>
</html>

image-20240308160626351

from apply02 import models
# 删全部
models.Book.objects.all().delete()
# 删除单行
models.Book.objects.filter(pk='1').delete()
# 删除多行
res = models.Book.objects.filter(title__icontains='5').delete()
    print(res)

分页

【1】示例

一个简单的分页的示例

# urls.py
from django.urls import path, re_path, include
from apply01 import views

urlpatterns = [
	# 插入数据
    re_path(r'^ab_pl/', views.ab_pl, name='ab_pl')
    # http://127.0.0.1:8080/ab_pl/?page=9
]
# views.py
from django.db import models
from apply02 import models
from django.shortcuts import render, HttpResponse, redirect,reverse
def ab_pl(request):
    # res_book = models.Book.objects.all()[0:10] # 切片
    # 想访问哪一页
    # 如果获取不到当前野马  就展示第一页
    current_page = request.GET.get('page', '1')
    # 想访问的页数
    # unsupported operand type(s) for -: 'str' and 'int'
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1
    # 每页展示多少条
    per_page_num = 10
    # 起始位置
    start_page = (current_page - 1) * per_page_num
    # 终止位置
    end_page = current_page * per_page_num
    # 切片
    res_book = models.Book.objects.all()[start_page:end_page]

    return render(request, 'books.html', locals())

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for book in res_book %}
    <p>{{ book.title }}</p>
{% endfor %}
</body>
</html>

image-20240308185144024

【2】适合分页的内置方法

  • divmod() 这个是用于执行除法和取余运算
divmod(a, b)
result = divmod(10, 3)
print(result)  # (3, 1)
  • 这个是每中不足的分页操作
# views.py
def ab_pl(request):
    # res_book = models.Book.objects.all()[0:10] # 切片
    # 书本的对象
    res_book = models.Book.objects.all()

    # 想访问哪一页
    # 如果获取不到当前野马  就展示第一页
    current_page = request.GET.get('page', '1')

    # 想访问的页数
    # unsupported operand type(s) for -: 'str' and 'int'
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1

    # 每页展示多少条
    per_page_num = 10

    # 动态计算出想要的总页数
    all_count = res_book.count()

    # 计算总数
    page_count,more = divmod(all_count,per_page_num)

    # 判断元组的第二个数据是否为0,从而确定到底需要多少页老展示数据
    if more:
        page_count += 1

    page_html = ''
    # 前端动态页面展示 - 后端写好页面传给前端
    for count in range(1, page_count + 1):
        page_html += f'<li><a href="?page={count}">{count}</a></li>'

    # 起始位置
    start_page = (current_page - 1) * per_page_num

    # 终止位置
    end_page = current_page * per_page_num

    # 切片
    res_book = models.Book.objects.all()[start_page:end_page]

    return render(request, 'books.html', locals())

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{% for book in res_book %}
    <p>{{ book.title }}</p>
{% endfor %}
<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {{ page_html|safe }}
        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>
</body>
</html>
  • 这是基本思路

【3】终版

  • 在制作页码个数的时候,一般情况下是奇数个
def ab_pl(request):
    # res_book = models.Book.objects.all()[0:10] # 切片
    # 书本的对象
    res_book = models.Book.objects.all()

    # 想访问哪一页
    # 如果获取不到当前野马  就展示第一页
    current_page = request.GET.get('page', '1')

    # 想访问的页数
    # unsupported operand type(s) for -: 'str' and 'int'
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1

    # 每页展示多少条
    per_page_num = 10

    # 动态计算出想要的总页数
    all_count = res_book.count()

    # 计算总数
    page_count,more = divmod(all_count,per_page_num)

    # 判断元组的第二个数据是否为0,从而确定到底需要多少页老展示数据
    if more:
        page_count += 1

    # 纠正左侧负数页数的问题
    left_page_count = current_page
    if current_page < 6:
        current_page = 6

    page_html = ''
    # 前端动态页面展示 - 后端写好页面传给前端
    for count in range(current_page -5 , current_page + 6):
        if left_page_count == count:
            page_html += f'<li class="active"><a href="?page={count}" >{count}</a></li>'
        else:
            page_html += f'<li><a href="?page={count}">{count}</a></li>'

    # 起始位置
    start_page = (current_page - 1) * per_page_num

    # 终止位置
    end_page = current_page * per_page_num

    # 切片
    res_book = models.Book.objects.all()[start_page:end_page]

    return render(request, 'books.html', locals())
{% for book in res_book %}
    <p>{{ book.title }}</p>
{% endfor %}
<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
{#        <li><a href="?page=1">1</a></li>#}
{#        <li><a href="?page=2">2</a></li>#}
{#        <li><a href="?page=3">3</a></li>#}
{#        <li><a href="?page=4">4</a></li>#}
{#        <li><a href="?page=5">5</a></li>#}
        {{ page_html|safe }}
        {# 前段转义 - 将后端的html页面进行转义,转为前端页码/也可以后端做这件事  #}
        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

【4】自定义分页器

  • 当我们需要使用分django内置的第三方功能或者组件代码的时候
  • 我们一般情况下会创建一个名为utils文件夹,在该文件夹内对模块进行功能性划分。
  • 优点就是可以在任何时候使用这个分页器方法
# 封装分页器 page.py
class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)
# 导入自定义的Pagination类的
from utils.page import Pagination
# 自定义分页
def ab_pl(request):
    # 获取数据
    res_book = models.Book.objects.all()
    # 获取第一页的数据
    current_page = request.GET.get('page',1)
    # 总页数
    all_count = res_book.count()
    # 传值生成对象
    page = Pagination(current_page=current_page,
                      all_count=all_count,
                      per_page_num=10)
    # 切片
    res_page = res_book[page.start:page.end]
    # 将res_page传递到页面 ,替换之前的res_book
    return render(request,'zibook.html',locals())

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{% for book in res_page %}
    <p>{{ book.title }}</p>
    <nav aria-label="Page navigation">

    </nav>
{% endfor %}

{{ page.page_html|safe }}
</body>
</html>

cnmOpenAi

‘’')
return ‘’.join(page_html_list)


```python
# 导入自定义的Pagination类的
from utils.page import Pagination
# 自定义分页
def ab_pl(request):
    # 获取数据
    res_book = models.Book.objects.all()
    # 获取第一页的数据
    current_page = request.GET.get('page',1)
    # 总页数
    all_count = res_book.count()
    # 传值生成对象
    page = Pagination(current_page=current_page,
                      all_count=all_count,
                      per_page_num=10)
    # 切片
    res_page = res_book[page.start:page.end]
    # 将res_page传递到页面 ,替换之前的res_book
    return render(request,'zibook.html',locals())

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <script src="{% static 'js/jquery-3.5.1.min.js' %}"></script>
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
{% for book in res_page %}
    <p>{{ book.title }}</p>
    <nav aria-label="Page navigation">

    </nav>
{% endfor %}

{{ page.page_html|safe }}
</body>
</html>

cnmOpenAi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1581637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AtCoder ABC347 A-D题解

个人感觉这次D有点难。 比赛链接:ABC347 Problem A: 签到题。 #include <bits/stdc.h> using namespace std; int main(){int N,K;cin>>N>>K;for(int i1;i<N;i){int A;cin>>A;if(A%K0)cout<<A/K;}return 0; } Problem B: 主要考substr的…

unity按路径移动

using System; using System.Collections; using System.Collections.Generic; using UnityEngine;public class FollowPathMove : MonoBehaviour {public Transform[] wayPointArray;[SerializeField] private Transform PathA;//路径点的父物体[SerializeField]private Trans…

紫光展锐T610平台_4G安卓核心板方案定制开发

紫光展锐T610核心板配备Android 11操作系统&#xff0c;采用12nm制程工艺。该处理器CPU由2颗基于Cortex-A75架构的大核心和6颗基于Cortex-A55架构的小核心组成&#xff0c;最高主频为1.8GHz。GPU采用的是614.4MHz的Mali G52&#xff0c;可以流畅播放2400*1080分辨率视频&#x…

MacOS初识SIP——解决快捷指令sh脚本报错Operation not permitted

前言 因为一些原因&#xff0c;设计了一套快捷指令&#xff0c;中间涉及到一个sh脚本的运行&#xff0c;通过快捷指令运行时就会报错&#xff1a;operation not permitted 奇怪的是在快捷指令窗口下运行一切正常&#xff0c;但是从其他地方直接调用&#xff0c;例如通过Comma…

典型新能源汽车热管理系统方案分析

目前行业具有代表性的热管理系统有PTC电加热方案、热泵方案&#xff08;特斯拉八通阀热泵、吉利直接式热泵&#xff09;、威马的柴油加热方案以及以理想为代表的插电式混动车方案。 小鹏P7整车热管理方案分析&#xff08;PTC电加热方案&#xff09; 小鹏P7作为小鹏汽车的第2款…

免费Docker容器服务Koyeb和Zeabur介绍及推荐

想搭建个演示站点仅是演示用。在哪找免费的云服务&#xff1f;还是有很多的。前面介绍过replit&#xff0c;这里介绍下几个提供免费云服务的的PaaS平台Koyeb和Zeabur&#xff0c;Zeabur平台或许是最好的选择。比如把个人的博客免费部署上去&#xff0c;也是个不错的选择呢。 前…

JVM字节码与类的加载——类的加载过程详解

文章目录 1、概述2、加载(Loading)阶段2.1、加载完成的操作2.2、二进制流的获取方式2.3、类模型与Class实例的位置2.4、数组类的加载 3、链接(Linking)阶段3.1、链接阶段之验证(Verification)3.1.1、格式检查3.1.2、字节码的语义检查3.1.3、字节码验证3.1.4、符号引用验证 3.2、…

PVE下安装配置openwrt和ikuai

开端 openwrt 和 ikuai 是比较出名的软路由系统。我最早接触软路由还是因为我的一个学长要改自己家里的网络&#xff0c;使用软路由去控制网络。我听说后便来了兴致&#xff0c;也在我家搞了一套软路由系统。现在我已经做完了&#xff0c;就想着写个文章记录一下。 软路由简介…

GFS部署实验

目录 1、部署环境 ​编辑 2、更改节点名称 3、准备环境 4、磁盘分区&#xff0c;并挂载 5. 做主机映射--/etc/hosts/ 6. 复制脚本文件 7. 执行脚本完成分区 8. 安装客户端软件 1. 安装解压源包 2. 创建gfs 3. 安装 gfs 4. 开启服务 9、 添加节点到存储信任池中 1…

应急响应-拒绝服务钓鱼指南DDOS压力测试邮件反制分析应用日志

知识点 1、CC攻击分析 2、钓鱼邮件分析 3、内网渗透分析 一、演示案例-内网应急-日志分析-爆破 MSSQL-1433 SMB-445 二、演示案例-红队APT-钓鱼邮件-内容&发信人&附件 如何分析邮件安全性&#xff1a; 1、看发信人地址 2、看发信内容信息 3、看发信内容附件 看后…

2011年认证杯SPSSPRO杯数学建模B题(第一阶段)生物多样性的评估全过程文档及程序

2011年认证杯SPSSPRO杯数学建模 B题 生物多样性的评估 原题再现&#xff1a; 2010 年是联合国大会确定的国际生物多样性年。保护地球上的生物多样性已经越来越被人类社会所关注&#xff0c;相关的大规模科研和考察计划也层出不穷。为了更好地建立国际交流与专家间的合作&…

UML2.0在系统设计中的实际使用情况

目前我在系统分析设计过程中主要使用UML2.0来表达&#xff0c;使用StarUML软件做实际设计&#xff0c;操作起来基本很顺手&#xff0c;下面整理一下自己的使用情况。 1. UML2.0之十三张图 UML2.0一共13张图&#xff0c;可以分为两大类&#xff1a;结构图-静态图&#xff0c;行…

学习Rust的第一天:基础知识

Introduction 介绍 I am Shafin Murani is a software development student and I am documenting every single day of my progress in learning rust. This is the first article of the series. Shafin Muranishi 是一名软件开发专业的学生&#xff0c;这是他在30天内记录学…

苹果电脑(Mac)怎么清理 itunes 备份?

苹果电脑用户广泛利用 iTunes 应用程序对 iPhone 或 iPad进行定期备份&#xff0c;以确保珍贵的数据安全无虞。然而&#xff0c;随着备份历史的增长&#xff0c;它们会在磁盘上积累大量空间&#xff0c;尤其当您频繁为多台设备备份时&#xff0c;存储资源可能会迅速消耗殆尽。为…

Docker部署Logstash同步Mysql数据到ES

1、准备配置文件文件夹 2、部署logstash & elasticsearch docker pull docker.elastic.co/logstash/logstash:7.15.0 ## 替换{你的ES地址}为ES地址 docker run -d --name logstash -p 5044:5044 -p 9600:9600 -v D:\logstash\data\:/usr/share/logstash/data -v D:\logst…

服务器数据恢复—V7000存储raid5数据恢复案例

服务器数据恢复环境&#xff1a; P740AIXSybaseV7000存储阵列柜&#xff0c;阵列柜上有12块SAS机械硬盘&#xff08;包括1块热备盘&#xff09;。 服务器故障&#xff1a; 管理员在日常巡检过程中发现阵列柜中有一块磁盘发生故障&#xff0c;于是更换磁盘并同步数据&#xff0…

Kafka基础/1

Kafka 概念 Kafka 是一个分布式的流媒体平台。 应用&#xff1a;消息系统、日志收集、用户行为追踪、流式处理 特点&#xff1a;高吞吐量、消息持久化、高可靠性、高扩展性 术语&#xff1a; broker&#xff1a;Kafka 的服务器&#xff0c;Kafka 当中每一台服务器&#xf…

Visual Studio Code 终端为管理员权限

第一部 1、 Visual Studio Code 快捷方式启动选项加上管理员启动 第二步 管理员方式运行 powershell Windows 10的任务栏自带了搜索。或者开始菜单选搜索只需在搜索框中输入powershell。 在出来的搜索结果中右击Windows PowerShell&#xff0c;然后选择以管理员方式运行。 执…

《前端面试题》- JS基础 - call()、apply()、bind() 的区别

call 、bind 、 apply 这三个函数的功能都是改变this的指向问题&#xff0c;但是也存在一定的区别。 call 的参数是直接放进去的&#xff0c;第二第三第 n 个参数全都用逗号分隔,apply 的所有参数都必须放在一个数组里面传进去bind 除了返回是函数以外&#xff0c;它 的参数和…

Training - 使用 WandB 配置 可视化 模型训练参数

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/137529140 WandB (Weights&Biases) 是轻量级的在线模型训练可视化工具&#xff0c;类似于 TensorBoard&#xff0c;可以帮助用户跟踪…