【一】Json
【1】介绍
- JSON(javascript object otaition)是一种轻量级的数据交换格式
- JSON使用了Javascript的一部分语法来定义其数据格式,但Json是独立于语言的
- Json采用完全独立于语言的文本格式,使得Json成为理想的数据交互语言,几乎所有的现代编程语言都也有工具可以解析Json
- 它是一种键值对形式的数据结构,易于人的阅读和编写,也易于机器的解析
- Json格式的提出
- 目的:取代繁琐笨重的XML格式
【2】格式
- 属性名必须使用双引号
- 不能使用十六进制值
- 不能使用undefind
- 不能使用日期和函数对象
{
"name": "John Doe",
"age": 30,
"is_student": false,
"subjects": ["Math", "English", "Science"],
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA"
}
}
【3】数据格式转换
【二】Ajax
【1】介绍
(1)概念
- AJAX(全称:Asynchronous JavaScript and XML,异步的Javascript和和XML)
- AJAX是一种无需重新加载整个页面的情况下,能够更新部分网页的技术
- 简单说:AJAX是一种用于创动态网页的编程技术
- 这意味着网页再被用户查看和交互的同时,可以与服务器进行数据交换和页面更新。
- 尽管名字中含有XML,但是在实践中,数据格式通常是JSON,并非XML
- 简单的将:异步交互、局部刷新
(2)大致工作原理
- 用户在浏览器进行操作(例如:点击一个按钮)
- Javascript创建一个XMLHttpRequest对象,然后向服务器发送请求
- 服务器处理这个请求
- 服务器将响应发送回网页
- Javascript读取响应,然后对网页进行响应的更新
- 关键:
- 关键是XMLHttpRequest对象
- 这个对象是AJAX的主要接口,他提供了浏览器和服务器之间的进行异步通信的能力
- 请求方式
- 既可以发送get请求又可以发送post请求
(3)请求方式小结
- 浏览器地址输入URL回车:GET请求
- a标签的跳转:GET请求
- form表单:既可以GET也可以POST
- AJAX:既可以GET也可以POST
【2】加法案例
(1)前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div>number_one: <input type="text" id="num1"></div>
<div>number_two: <input type="text" id="num2"></div>
<div>result: <input type="text" id="result"></div>
<button id="btn_result">求和计算</button>
<script>
{#等待页面加载完毕#}
$(document).ready(
{#给按钮绑定事件#}
$("#btn_result").click(function () {
{#异步触发AJAX#}
$.ajax(
{
{#提交数数据路径, 和action一样#}
url: "",
{#提交方式#}
type: "post",
{#表示期望从数据库返回的数据类型(json、xml、script、html)#}
dataType:"json",
{#提交给后端的数据, 键值可以直接写#}
data: {
number1: $("#num1").val(),
"number2": $("#num2").val()
},
{#回调函数,data是后端返回的数据#}
success: function (data) {
console.log(data, typeof data)
{#102 string#}
$("#result").val(data)
}
}
)
})
)
</script>
</body>
</html>
(2)后端
from django.shortcuts import render, HttpResponse, JsonResponse
def home(request):
if request.method == "POST":
data = request.POST
print(data)
num1 = data.get("number1")
num2 = data.get("number2")
result = int(num1) + int(num2)
return HttpResponse(result)
return JsonResponse(result)
return render(request, 'home.html')
(3)不同方式数据返回
-
在Django框架中,
HttpResponse
和JsonResponse
是两种不同的响应方式。HttpResponse
通常用于返回文本数据JsonResponse
用于返回JSON格式的数据
-
如果后端使用
HttpResponse
返回数据- 那么数据(包括字典)将作为字符串返回,客户端(例如JavaScript)需要手动对其进行解析或反序列化。
- 例如,如果返回的是JSON格式的字符串,那么在JavaScript中,需要使用
JSON.parse()
函数将其转换为JavaScript对象。 - 或者在后端中使用
json.dumps()
方法将数据转换成
-
如果后端使用
JsonResponse
返回数据- 那么Django将自动将Python字典或列表转换为JSON格式的字符串。
- 在客户端,如果使用的是JavaScript的
fetch
API或jQuery的$.ajax
方法(并且dataType
参数被设置为'json'
),那么这些函数将自动将JSON字符串转换为JavaScript对象,无需手动进行反序列化。
<script>
{#等待页面加载完毕#}
$(document).ready(
{#给按钮绑定事件#}
$("#btn_result").click(function () {
{#异步触发AJAX#}
$.ajax(
{
{#提交数数据路径, 和action一样#}
url: "",
{#提交方式#}
type: "post",
{#表示期望从数据库返回的数据类型(json、xml、script、html)#}
dataType: "json",
{#提交给后端的数据, 键值可以直接写#}
data: {
number1: $("#num1").val(),
"number2": $("#num2").val()
},
{#回调函数,data是后端返回的数据#}
success: function (data) {
console.log(data, typeof data)
{#{message: 'OK', result: 7712}#}
{# 'object'#}
$("#result").val(data.result)
}
}
)
})
)
</script>
def home(request):
if request.method == "POST":
data = request.POST
print(data)
num1 = data.get("number1")
num2 = data.get("number2")
res = {
"message": "OK",
"result": int(num1) + int(num2)
}
return JsonResponse(res)
return render(request, 'home.html')
【三】前后端传输数据的编码格式(contentType)
- 由于get请求数据是直接放在url后面的
- url?username=bruce&password=123
- 所以主要研究POST请求
【1】urlencoded
- application/x-www-form-urlencoded(urlencoded)
- 这是最常见的POST数据提交的方式。
- 浏览器的原生
<form>
表单,如果不设置 enctype 属性,那么最终就会以application/x-www-form-urlencoded
方式提交数据。 - 键值对都是通过**&符号分隔,键值之间等号(=**)连接。
- 例如:
key1=value1&key2=value2
。
- 例如:
【2】formdata
- multipart/form-data(formdata)
- 这种数据格式通常用于文件上传。
- 当表单中包含
<input type="file">
时,就需要使用这种格式来提交表单。
【3】json
- application/json(json)
- 这种数据格式用于发送 JSON 格式的数据。
- 在现代的Web应用中,这种格式越来越常见,特别是在构建 RESTful API 时。
- form表单没有这种格式
【4】plain
-
表单
<form>
的enctype
属性还可以设置为text/plain
-
text/plain
是一种简单的数据格式- 它和
application/x-www-form-urlencoded
类似 - 但是它不对字符进行URL编码
- 这意味着,如果你的数据中包含特殊字符(例如空格、
&
、=
等),这些字符在text/plain
格式中将保持原样,而不会被转换为URL编码。- 空格被转换为
+
,@
被转换为%40
·
- 空格被转换为
- 它和
-
ext/plain
格式并不常用,因为它不进行URL编码,可能会导致数据传输过程中出现问题。
【四】AJAX传输数据编码格式
【1】request补充
(1).body
- 在 Django 中,
request.body
属性包含了 HTTP 请求的原始内容,它通常用于处理非表单数据的 POST 请求。- 比如,当发送 JSON、XML 或者其他类型的数据时,你会使用
request.body
来获取这些数据。
- 比如,当发送 JSON、XML 或者其他类型的数据时,你会使用
request.body
返回的是一个字节字符串- 所以如果你发送的是 JSON 数据,你需要使用 Python 的
json
模块来解析这个字节字符串
- 所以如果你发送的是 JSON 数据,你需要使用 Python 的
- 需要注意的是,
request.body
只能被读取一次- 因为它是从 socket 读取的,读取后数据就会被清空。
- 如果试图多次读取
request.body
,你会得到一个空的字节字符串。 - 如果需要多次使用请求的数据,你需要将它保存到一个变量中。
- 要使用尽量放在最千面
(2).is_ajax()
-
is_ajax()
是HttpRequest对象的一个方法- 它用于检查HTTP请求是否是一个AJAX请求。
- 这个方法检查HTTP请求头中的
X-Requested-With
字段是否为XMLHttpRequest
。 - 如果是,则返回
True
,否则返回False
。
-
需要注意的是,
is_ajax()
方法并不完全可靠- 因为它依赖于客户端设置正确的
X-Requested-With
头。 - 如果一个恶意的客户端发送一个伪造的请求,并设置
X-Requested-With
为XMLHttpRequest
,那么is_ajax()
会错误地认为这是一个AJAX请求。
- 因为它依赖于客户端设置正确的
【2】默认格式
(1)前端界面
<button class="btn btn=success" id="b1">Click</button>
<script>
$(document).ready(
$("#b1").click(function () {
$.ajax({
url: "",
type: "post",
data: {"username": "bruce", "password": "123"},
success: function (args) {
}}
)
})
)
</script>
(2)后端
def home(request):
body = request.body
print(body, type(body))
if request.method == "POST":
data = request.POST
print(data, type(data))
return render(request, 'home.html')
# b'username=bruce&password=123' <class 'bytes'>
# <QueryDict: {'username': ['bruce'], 'password': ['123']}> <class 'django.http.request.QueryDict'>
(3)结果
- 默认值是
'application/x-www-form-urlencoded; charset=UTF-8'
,这表示数据是以表单的形式提交的。- 特殊的字符串类型
- 编码方式将每个键值对(key-value pair)转换为
key=value
的形式,并使用&
符号连接多个键值对。
【3】Json格式
(1)前端页面
<button class="btn btn=success" id="b1">Click</button>
<script>
$(document).ready(
$("#b1").click(function () {
$.ajax({
url: "",
type: "post",
contentType:"applications/json",
data: JSON.stringify({"username": "bruce", "password": "123"}),
success: function (args) {
}}
)
})
)
</script>
(2)后端
def home(request):
body = request.body
print(body, type(body))
if request.method == "POST":
data = request.POST
print(data, type(data))
if body:
# 先解码
json_str = body.decode('utf-8')
# 类型转换
json_dict = json.loads(json_str)
print(json_dict, type(json_dict))
return render(request, 'home.html')
b'{"username":"bruce","password":"123"}' <class 'bytes'>
<QueryDict: {}> <class 'django.http.request.QueryDict'>
{'username': 'bruce', 'password': '123'} <class 'dict'>
# 在没有设置类型时
# b'{"username":"bruce","password":"123"}' <class 'bytes'>
# <QueryDict: {'{"username":"bruce","password":"123"}': ['']}> <class 'django.http.request.QueryDict'>
(3)结果
-
contentType:"applications/json"
-
首先在没有上述设置之前
- 默认按照urlencoded格式
- 是特殊的字符串格式
- 所以在POST中看到的是
<QueryDict: {'{"username":"bruce","password":"123"}': ['']}> <class 'django.http.request.QueryDict'>
- 将所有的数据当成连连在一起的字符,作为一个键值传入
-
在添加上述设置以后
- 我们在POST中拿不到任何数据了,是一个空的querydict
- 我们此时只能在body中拿去数据
- 但是该数据是字节字符串
- 所以需要先解码
- 在使用json.loads()转换格式后
- 才可以拿到想要的数据
【4】文件格式
(1)前端界面
<p>username: <input type="text" id="d1" name="username"></p>
<p>username: <input type="password" id="d2" name="password"></p>
<p>file: <input type="file" id="d3" name="file"></p>
<button class="btn btn-success" id="b1">submit</button>
<script>
$("#b1").on('click', function () {
{#传输文件需要内置对象formdata#}
let formDataObj = new FormData();
formDataObj.append('username', $("#d1").val());
formDataObj.append('password', $("#d2").val());
formDataObj.append('file', $("#d3")[0].files[0]);
$.ajax({
url: "",
type: "post",
data: formDataObj,
{#不需要使用任何编码,django后端能自动识别formdate对象#}
contentType: false,
{#告诉浏览器不要对我的数据进行处理#}
processData: false,
success: function (args) {
}
})
})
</script>
(2)后端
def home(request):
if request.is_ajax() and request.method == "POST":
print(request.POST)
print(request.FILES)
return render(request, 'home.html')
# <QueryDict: {'username': ['456'], 'password': ['123']}>
# <MultiValueDict: {'file': [<InMemoryUploadedFile: 53efb9d8079c6e4f904ed602f5c1e4e.png (image/png)>]}>
(3)结果
-
想要传输文件需要
- javascript内置对象
- formdata
- 可以通过append方法
- 添加在键值对
- 文件内容在
$("#d1")[0].files[0]
中
- 两个配置
- 不使用任何编码
contentType: false
,后端自动识别formdata - 不对数据进行任何处理:
processData: false
- 不使用任何编码
- javascript内置对象
-
后端可以通过is_ajax和post一起来判断
- 是否是ajax的post请求
- 文件在
request.FILES
中 - 其他键值对在
request.POST
中
【五】sweetleart
【1】官网
(1)sweetleart1
- SweetAlert1
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
- 其他需要的资源
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
(2)sweetleart2
-
sweetalert2 CDN by jsDelivr - A CDN for npm and GitHub
-
SweetAlert2
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
- 其他资源对象
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
【2】使用
(1)弹框后跳转
<button class="btn btn-success" id="b1">submit</button>
<script>
$("#b1").on('click', function () {
Swal.fire({
position: "top-end",
icon: "success",
title: "Your work has been saved",
showConfirmButton: false,
timer: 1500
}).then(function () {
$.ajax({
type: "POST",
url: "",
data: "",
success: function () {
window.location.href = "https://www.baidu.com/";
},
});
});
});
</script>
(2)确认删除后跳转
- 点击确认后将段落ID传递给后端
- 后端返回可以的信息和新的地址
- 然后自动跳转到新界面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
</head>
<body>
<p id="p1">
<button class="btn btn-success" id="b1">submit</button>
</p>
<script>
$("#b1").on('click', function () {
Swal.fire({
title: "Are you sure?",
text: "You won't be able to revert this!",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Yes, delete it!"
}).then((result) => {
if (result.isConfirmed) {
var pId = $("#p1").attr("id");
$.ajax({
type: "POST",
url: "",
data: {pId: pId},
success: function (response) {
if (response.flag) {
Swal.fire({
title: "Deleted!",
text: "Your file has been deleted.",
icon: "success"
}).then(() => {
window.location.href = response.url;
});
}
},
});
}
});
});
</script>
</body>
</html>
def home(request):
if request.is_ajax() and request.method == "POST":
data_dict = {"flag": True, "url": "https://www.baidu.com/"}
return JsonResponse(data_dict)
return render(request, 'home.html', locals())
【六】序列化组件
【0】前言
(1)为啥要用
-
目前我们可以在后端通过models获得queryset对象
- 然后直接用locals()直接传送给前端
-
但是在前后端分离项目中
-
queryset对象的内容格式是多种多样的
-
前端工程师无法简单的了解你的数据格式
-
所以需要一种统一的格式
-
一般都是将数据处理成列表套字典的形式
-
[{}, {}, {}...]
-
(2)模型数据准备
- 模型
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField(null=True)
gender_choices = (
(1, "男"),
(2, "女"),
(3, "保密"),
)
gender = models.IntegerField(choices=gender_choices, default=3)
- 批量添加数据(后续具体讲解)
import random
from django.test import TestCase
# Create your tests here.
import os
if __name__ == '__main__':
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
import django
django.setup()
from app01 import models
user_list = []
for i in range(5):
obj = models.User(name=f"bruce{i}", age=20+i, gender=random.choice([1, 2, 3]))
user_list.append(obj)
models.User.objects.bulk_create(user_list)
【1】JsonResponse
- 后端发送数据
def home(request):
user_queryset = models.User.objects.all()
user_list = []
for user_obj in user_queryset:
user_dict = {"name": user_obj.name,
"age": user_obj.age,
"gender": user_obj.gender}
user_list.append(user_dict)
return JsonResponse(user_list, safe=False)
- 前端拿到的数据格式
[
{
"name": "bruce0",
"age": 20,
"gender": 2
},
{
"name": "bruce1",
"age": 21,
"gender": 1
},
{
"name": "bruce2",
"age": 22,
"gender": 2
},
{
"name": "bruce3",
"age": 23,
"gender": 3
},
{
"name": "bruce4",
"age": 24,
"gender": 2
}
]
【2】serializers组件
- 后端
from django.core import serializers
def home(request):
user_queryset = models.User.objects.all()
user_str = serializers.serialize('json', user_queryset)
print(type(user_str))
# <class 'str'>
return HttpResponse(user_str)
- 前端
- 这里面的信息就更加丰富了
- 有model、pk和fields
- 其中fields中是模型型中的具体数据
[{"model": "app01.user", "pk": 1, "fields": {"name": "bruce0", "age": 20, "gender": 2}}, {"model": "app01.user", "pk": 2, "fields": {"name": "bruce1", "age": 21, "gender": 1}}, {"model": "app01.user", "pk": 3, "fields": {"name": "bruce2", "age": 22, "gender": 2}}, {"model": "app01.user", "pk": 4, "fields": {"name": "bruce3", "age": 23, "gender": 3}}, {"model": "app01.user", "pk": 5, "fields": {"name": "bruce4", "age": 24, "gender": 2}}]
【3】小结
- JsonResponse
- 为了统一的列表套字典格式
- 需要手动创建该格式
- serializers
- 首先需要导入模块
- 然后用模块转换数据格式
- 最后HttpResponse传输数据
- 都有的问题
- 这里的性别在前端开来,只有三个数字
- 不知具体含义
- 所有都还需要有一个具体字段数值说明书