Python Web开发记录 Day13:Django part7 Ajax入门与案例(任务管理)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪)
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)目录
- 1、Ajax入门
- ①简介
- ②工作原理
- ③优点
- ④缺点
- ⑤使用
- 2、GET/POST与Ajax请求
- ①GET/POST
- ②Ajax
- ③GET请求
- ④POST请求
- 3、返回值
- ①以json的方式返回数据
- ②补充:json
- ③后台接收输入框内容
- 4、Ajax案例(任务管理)
- ①任务添加(一)
- ②任务添加(二)
- ③数据保存及校验
1、Ajax入门
①简介
AJAX,全称为"Asynchronous JavaScript and XML"(异步的JavaScript和XML),是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实现异步更新。这意味着可以在页面不进行全面刷新的情况下,更新其部分内容。这样不仅可以减少数据传输量,还能提高网页的交互性。
②工作原理
AJAX的工作原理基于以下几个关键技术:
- XMLHttpRequest对象(XHR):负责与服务器异步交换数据。通过这个对象发送请求并接收响应,开发者可以在不重新加载页面的情况下更新网页的某一部分。
- JavaScript/DOM:用于动态显示和交互。
- CSS:用于定义数据的样式。
- XML:曾经是数据交换的主要格式,但现在JSON格式因为其轻量和易于解析的特性,已经成为更受欢迎的数据交换格式。
③优点
- 提高用户体验:通过局部刷新页面内容,减少等待时间和服务器响应时间,从而提高用户体验。
- 减轻服务器负担:仅请求必要的数据,而不是整个页面的数据,减少了带宽的使用和服务器的负担。
- 支持异步通信:页面可以在等待服务器响应的同时,继续处理其他事务,提高了应用程序的效率。
④缺点
- SEO问题:由于AJAX加载的内容可能不会被搜索引擎爬虫抓取,因此可能影响页面的SEO。
- 兼容性问题:虽然现代浏览器都支持AJAX,但在一些旧浏览器中可能存在兼容性问题。
- 安全问题:由于AJAX涉及到异步数据交换,可能会引入跨站脚本攻击(XSS)等安全问题。
⑤使用
一个简单的AJAX使用示例,假设我们想异步从服务器获取一些数据,并在网页上显示这些数据,可以使用以下JavaScript代码:
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
xhr.open("GET", "server.php", true); // 配置请求类型、URL及异步处理方式
xhr.onreadystatechange = function() { // 设定回调函数if (xhr.readyState == 4 && xhr.status == 200) {document.getElementById("myDiv").innerHTML = xhr.responseText; // 处理服务器响应}
};
xhr.send(); // 发送请求
这段代码演示了如何创建XMLHttpRequest
对象,配置请求,并在收到服务器响应后更新页面元素内容。
Ajax技术自从2005年被广泛推广以来,已经成为现代网页开发不可或缺的一部分。尽管它存在一些缺点和挑战,但其对于提升用户体验和页面性能的贡献是毋庸置疑的。随着Web技术的不断发展,AJAX也在不断进化,配合现代前端框架和库(如React、Vue、Angular),能够构建出更加动态和交互流畅的网页应用。
2、GET/POST与Ajax请求
①GET/POST
浏览器向网站发送请求时,URL和表单的形式提交的两种请求方法,GET
和POST
,它们是两种常用的HTTP请求方法,用于在客户端和服务器之间传输数据。
-
GET方法 用于请求从指定的资源获取数据。使用GET请求时,请求的参数会附加在URL之后,以
?
分隔URL和传输数据,参数之间以&
连接。例如,http://example.com/index?name1=value1&name2=value2
。GET请求通常用于请求页面、图片或者进行查询操作,它的特点是简单且无副作用,但是由于参数直接暴露在URL中,所以不适合传输敏感信息。 -
POST方法 用于向指定的资源提交要被处理的数据。与GET方法不同,POST方法的数据不会附加在URL之后,而是放在HTTP请求的正文(body)中。这意味着数据的大小和类型都没有GET那么严格的限制,同时也更加安全,因为数据不会直接暴露在URL中。POST请求常用于提交表单数据、上传文件等需要“写”操作的场景。
在Python中,可以使用多种方式发起GET和POST请求,最常见的库之一是requests
库。以下是使用requests
库发起GET和POST请求的基本示例:
GET请求示例:
import requestsresponse = requests.get('http://example.com/api/data?name1=value1&name2=value2')
print(response.text) # 打印响应内容
POST请求示例:
import requestsdata = {'name1': 'value1', 'name2': 'value2'}
response = requests.post('http://example.com/api/data', data=data)
print(response.text) # 打印响应内容
需要注意的是,为了安全起见,敏感信息应避免通过GET请求传输,而应选择POST请求。此外,使用这些请求方法时,应该考虑到HTTP协议的特点和限制。
特点:页面刷新
②Ajax
与上述两种方式对比,Ajax可以实现向后台悄悄地发送请求。
- 依赖jQuery
- 编写Ajax代码
$.ajax({url:"发送的地址",type:"get",data:{n1:123,n2:456},success:function(res){console.log(res);}
})
③GET请求
1.在urls.py中添加任务列表的路径
task/list/
以及task/ajax/
,并告诉该路径指向的视图task_list
from django.urls import path
from api.views import depart, user, pretty, admin, account, taskurlpatterns = [# 部门管理path("depart/list/", depart.depart_list),path("depart/add/", depart.depart_add),path("depart/delete/", depart.depart_delete),path("depart/<int:nid>/edit/", depart.depart_edit),# 用户管理path("user/list/", user.user_list),path("user/add/", user.user_add),path("user/model/form/add/", user.user_model_form_add),path('user/<int:nid>/edit/', user.user_edit),path("user/<int:nid>/delete/", user.user_delete),# 靓号管理path("pretty/list/", pretty.pretty_list),path("pretty/add/", pretty.pretty_add),path("pretty/<int:nid>/edit/", pretty.pretty_edit),path("pretty/<int:nid>/delete/", pretty.pretty_delete),# 管理员管理path('admin/list/', admin.admin_list),path('admin/add/', admin.admin_add),path('admin/<int:nid>/edit/', admin.admin_edit),path('admin/<int:nid>/delete/', admin.admin_delete),path('admin/<int:nid>/reset/', admin.admin_reset),# 用户登录path('login/', account.login),path('logout/', account.logout),path('image/code/', account.image_code),# 任务管理path('task/list/',task.task_list),path('task/ajax/',task.task_ajax),
]
2.在views文件夹下新建task.py,并在task.py中写出对应的函数,发出请求,并返回响应
task_list.html
task.py
from django.shortcuts import render,HttpResponsedef task_list(request):return render(request,"task_list.html")def task_ajax(request):print(request.GET)return HttpResponse("成功了")
3.创建templates目录下模版html文件task_list.html,以此呈现做任务列表的界面。
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input type="button" value="点击" class="btn btn-primary" onclick="clickMe();"></div>
{% endblock %}{% block script %}<script type="text/javascript">function clickMe() {$.ajax({url: '/task/ajax/',type: "get",data: {n1:123,n2:456},success: function(res) {console.log(res);}})}</script>
{% endblock %}
效果:
按F12打开调试页面,可以看到"成功了"。
④POST请求
1.在urls.py中添加任务列表的路径
task/list/
以及task/ajax/
,并告诉该路径指向的视图task_list
from django.urls import path
from api.views import depart, user, pretty, admin, account, taskurlpatterns = [# 部门管理path("depart/list/", depart.depart_list),path("depart/add/", depart.depart_add),path("depart/delete/", depart.depart_delete),path("depart/<int:nid>/edit/", depart.depart_edit),# 用户管理path("user/list/", user.user_list),path("user/add/", user.user_add),path("user/model/form/add/", user.user_model_form_add),path('user/<int:nid>/edit/', user.user_edit),path("user/<int:nid>/delete/", user.user_delete),# 靓号管理path("pretty/list/", pretty.pretty_list),path("pretty/add/", pretty.pretty_add),path("pretty/<int:nid>/edit/", pretty.pretty_edit),path("pretty/<int:nid>/delete/", pretty.pretty_delete),# 管理员管理path('admin/list/', admin.admin_list),path('admin/add/', admin.admin_add),path('admin/<int:nid>/edit/', admin.admin_edit),path('admin/<int:nid>/delete/', admin.admin_delete),path('admin/<int:nid>/reset/', admin.admin_reset),# 用户登录path('login/', account.login),path('logout/', account.logout),path('image/code/', account.image_code),# 任务管理path('task/list/',task.task_list),path('task/ajax/',task.task_ajax),
]
2.在views文件夹下新建task.py,并在task.py中写出对应的函数,发出请求,并返回响应
task_list.html
task.py
from django.shortcuts import render,HttpResponsedef task_list(request):return render(request,"task_list.html")def task_ajax(request):print(request.GET)return HttpResponse("成功了")
3.创建templates目录下模版html文件task_list.html,以此呈现做任务列表的界面。
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input type="button" value="点击" class="btn btn-primary" onclick="clickMe();"></div>
{% endblock %}{% block script %}<script type="text/javascript">function clickMe() {$.ajax({url: '/task/ajax/',type: "get",data: {n1:123,n2:456},success: function(res) {console.log(res);}})}</script>
{% endblock %}
效果:
后台输出:
优化上面的Ajax代码:绑定事件
,使其能够在页面框架加载完成之后自动执行代码。
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击" class="btn btn-primary">
</div>{% endblock %}{% block script %}
<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},success: function (res) {console.log(res);}})})}
</script>
{% endblock %}
3、返回值
①以json的方式返回数据
修改前端task_list.html中的bindBtn1Event()函数。
function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},{#修改1#}dataType: "JSON",success: function (res) {console.log(res);{#修改2#}console.log(res.status);console.log(res.data);}})})
}
修改后端:
import json
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exemptdef task_list(request):return render(request, "task_list.html")@csrf_exempt
def task_ajax(request):print("get请求:", request.GET)print("POST请求", request.POST)data_dict = {"status": True, 'data': [11, 22, 33, 44]}return HttpResponse(json.dumps(data_dict))
效果:
到了,这里可能会有疑问,json数据?什么是json?
②补充:json
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。JSON格式是独立于语言的,尽管它是由JavaScript的对象字面量语法派生而来的,但是JSON格式的数据可以由多种语言读取,如Python、Ruby、PHP等。
1.JSON的结构
JSON格式支持两种结构:
- 键/值对集合:在各种语言中,这被实现为对象、记录、结构、字典、哈希表、有键列表,或者关联数组。
- 有序的值列表:在大多数语言中,这被实现为数组、向量、列表或序列。
JSON的基本类型包括数字(整数或浮点数)、字符串(在双引号中)、布尔值(true
或false
)、数组(在方括号中)、对象(在大括号中的键/值对)和null
。
2.JSON示例
以下是一个简单的JSON对象示例,它描述了一个人的信息:
{"name": "张三","age": 30,"isStudent": false,"hobbies": ["旅游", "摄影"],"address": {"street": "科技园路.","city": "深圳","postalCode": "518057"}
}
在这个例子中,我们可以看到字符串、数字、布尔值、数组和嵌套对象的使用。
3.在Python中使用JSON
在Python中,可以使用json
模块来解析JSON字符串和生成JSON格式的字符串。以下是一些基本的操作:
解析JSON字符串
import json# JSON字符串
json_str = '{"name": "张三", "age": 30, "isStudent": false}'# 解析JSON字符串
data = json.loads(json_str)# 使用数据
print(data['name']) # 输出:张三
生成JSON字符串
import json# Python字典
data = {"name": "李四","age": 25,"isStudent": True
}# 生成JSON格式的字符串
json_str = json.dumps(data, ensure_ascii=False)print(json_str) # 输出:{"name": "李四", "age": 25, "isStudent": true}
关于json.dumps:
json.dumps
是Python中的一个函数,属于 json
模块。它用于将Python对象编码成JSON格式的字符串。
具体来说,json.dumps函数接受Python的数据类型,如字典、列表、字符串等,并将其转换为一个字符串,这个字符串表示相同数据的JSON格式。这对于数据存储、网络传输等场景非常有用。
举个例子:
import jsondata = {'name': '张三', 'age': 30, 'city': '北京'}
json_str = json.dumps(data, ensure_ascii=False)print(json_str)
这段代码会输出:
{"name": "张三", "age": 30, "city": "北京"}
在这个例子中:
import json
引入了json
模块,使得json.dumps
函数可用。data
是一个Python字典,包含了一些键值对。json.dumps(data, ensure_ascii=False)
调用了json.dumps
函数,将data
转换成了JSON格式的字符串。ensure_ascii=False
参数指示json.dumps
使用UTF-8编码,这样可以正确显示中文而不是Unicode编码。
这样,Python中的数据就可以被转换为JSON字符串,便于存储或在网络中传输。
③后台接收输入框内容
1.修改task_list.html
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击" class="btn btn-primary"><h3>示例2</h3><input type="text" id="txtuser" placeholder="姓名"><input type="text" id="txtpwd" placeholder="密码"><input id="btn2" type="button" value="点击" class="btn btn-primary"></div>{% endblock %}{% block script %}
<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})
}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}
</script>
{% endblock %}
效果:
这样是实现了,但是如果前端代码过多的话,又该怎么办呢?此时我们就需要用更简单的方法来进行批量处理了。
2.再次修改task_list.html
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击1" class="btn btn-primary"><h3>示例2</h3><input type="text" id="txtuser" placeholder="姓名"><input type="text" id="txtpwd" placeholder="密码"><input id="btn2" type="button" value="点击2" class="btn btn-primary"><form id="from3"><h3>示例3</h3><input type="text" name="user" placeholder="姓名"><input type="text" name="age" placeholder="年龄"><input type="text" name="pwd" placeholder="密码"><input type="text" name="mobile" placeholder="电话"></form><input id="btn3" type="button" value="点击3" class="btn btn-primary"></div>{% endblock %}{% block script %}
<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();bindBtn3Event();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn3Event() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}
</script>
{% endblock %}
效果:
至此,如何在浏览器不刷新的情况下,向后台提交数据的问题也就解决了。
4、Ajax案例(任务管理)
①任务添加(一)
1.在models.py中创建任务Task表。
models.py
class Task(models.Model):"""任务"""level_choices = ((1, "紧急"),(2, "重要"),(3, "临时"),)level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)title = models.CharField(verbose_name="标题", max_length=64)detail = models.TextField(verbose_name="详细信息")user = models.ForeignKey(verbose_name="负责人", to=Admin, on_delete=models.CASCADE)
之后更新数据库表:
python manage.py makemigrations
python manage.py migrate
经过上述命令之后,可以看到task表已经添加完成。
启动Django项目的开发服务器,方便测试Django搭建的系统:
python manage.py runserver
具体来讲:
python
是启动Python解释器的命令。manage.py
是Django项目中的一个脚本,用于执行项目相关的各种命令。runserver
是传递给manage.py
的一个参数,它指示Django启动一个轻量级的Web服务器,用于开发和测试。
默认情况下,该服务器运行在本地的8000端口(http://127.0.0.1:8000/
),但你可以通过添加端口号来改变它,例如 runserver 8080
会让服务器运行在8080端口。
2.修改task.py
task.py
from employee_management.utils.modelform import BootStrapModelForm
from employee_management.models import Taskclass TaskModelForm(BootStrapModelForm):class Meta:model = Taskfields = "__all__"@csrf_exempt
def task_list(request):form = TaskModelForm()return render(request, "task_list.html", {"form": form})
3.修改task_list.html
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading">表单</div><div class="panel-body"><form method="post" novalidate>{% for item in form %}<div class="form-group"><label>{{ item.label }}</label>{{ item }}</div>{% endfor %}</form></div></div><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击1" class="btn btn-primary"><h3>示例2</h3><input type="text" id="txtuser" placeholder="姓名"><input type="text" id="txtpwd" placeholder="密码"><input id="btn2" type="button" value="点击2" class="btn btn-primary"><form id="from3"><h3>示例3</h3><input type="text" name="user" placeholder="姓名"><input type="text" name="age" placeholder="年龄"><input type="text" name="pwd" placeholder="密码"><input type="text" name="mobile" placeholder="电话"></form><input id="btn3" type="button" value="点击3" class="btn btn-primary"></div>{% endblock %}{% block script %}<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();bindBtn3Event();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn3Event() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}</script>
{% endblock %}
其实到这里 ,虽然界面已经出来了,但是这个界面占整个页面的篇幅太大了,因此我们要优化一下前端的展示页面,以使整体更加和谐。
4.修改task_list.html
注意,下面前端代码里的button必须放在form表单外,否则submit的ajax触发机制不会生效。
原因如下:
在HTML中,如果将button
标签放置在form
标签内部,并且没有指定type
属性或将type
属性设为submit
,当按钮被点击时,默认触发表单的提交。如果你希望使用button
进行AJAX操作而不提交表单,你有两种选择:
- 将
button
标签放置在form
标签之外。 - 在
form
标签内部使用button
标签,但要将button
的type
属性设置为button
。
例如:
<!-- 将button放在form外面 -->
<button id="ajaxButton">AJAX 请求按钮</button>
<form id="myForm"><!-- 表单内容 -->
</form><!-- 或者在form内部将button类型设为button -->
<form id="myForm"><!-- 表单内容 --><button type="button" id="ajaxButton">AJAX 请求按钮</button>
</form>
在这种情况下,即使button
位于form
内部,由于其类型被设置为button
,点击时不会触发表单的提交。这样,你就可以绑定AJAX调用到这个按钮上,而不干扰表单的正常提交逻辑。
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading">表单</div><div class="panel-body"><form method="post" id="task_form" novalidate><div>{% for item in form %}<div class="col-xs-6"><div class="form-group"><label>{{ item.label }}</label>{{ item }}</div></div>{% endfor %}</div></form><div class="col-xs-12"><input id="submit" type="submit" value="提 交" class="btn btn-primary center-block" style="width: 100px;"></div></div></div><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击1" class="btn btn-primary"><h3>示例2</h3><input type="text" id="txtuser" placeholder="姓名"><input type="text" id="txtpwd" placeholder="密码"><input id="btn2" type="button" value="点击2" class="btn btn-primary"><form id="from3"><h3>示例2</h3><input type="text" name="user" placeholder="姓名"><input type="text" name="age" placeholder="年龄"><input type="text" name="pwd" placeholder="密码"><input type="text" name="mobile" placeholder="电话"></form><input id="btn3" type="button" value="点击3" class="btn btn-primary"></div>{% endblock %}{% block script %}
<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();bindBtn3Event();bindaddEvent();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn3Event() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindaddEvent() {$("#submit").click(function () {$.ajax({url: '/task/add/',type: "post",data: $("#task_form").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}
</script>
{% endblock %}
效果:
②任务添加(二)
1.在urls.py中添加任务列表的路径
task/add/
,并告诉该路径指向的视图task_add
urls.py
from django.urls import path
from api.views import depart, user, pretty, admin, account, taskurlpatterns = [# 部门管理path("depart/list/", depart.depart_list),path("depart/add/", depart.depart_add),path("depart/delete/", depart.depart_delete),path("depart/<int:nid>/edit/", depart.depart_edit),# 用户管理path("user/list/", user.user_list),path("user/add/", user.user_add),path("user/model/form/add/", user.user_model_form_add),path('user/<int:nid>/edit/', user.user_edit),path("user/<int:nid>/delete/", user.user_delete),# 靓号管理path("pretty/list/", pretty.pretty_list),path("pretty/add/", pretty.pretty_add),path("pretty/<int:nid>/edit/", pretty.pretty_edit),path("pretty/<int:nid>/delete/", pretty.pretty_delete),# 管理员管理path('admin/list/', admin.admin_list),path('admin/add/', admin.admin_add),path('admin/<int:nid>/edit/', admin.admin_edit),path('admin/<int:nid>/delete/', admin.admin_delete),path('admin/<int:nid>/reset/', admin.admin_reset),# 用户登录path('login/', account.login),path('logout/', account.logout),path('image/code/', account.image_code),# 任务管理path('task/list/', task.task_list),path('task/ajax/', task.task_ajax),path('task/add/', task.task_add),
]
2.修改task.py
task.py
import jsonfrom django import forms
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from api.utils.form import BootStrapModelForm
from api.models import Taskclass TaskModelForm(BootStrapModelForm):class Meta:model = Taskfields = "__all__"widgets = {"detail": forms.TextInput,}@csrf_exempt
def task_list(request):form = TaskModelForm()return render(request, "task_list.html", {"form": form})@csrf_exempt
def task_ajax(request):print("get请求:", request.GET)print("POST请求", request.POST)data_dict = {"status": True, 'data': [11, 22, 33, 44]}return HttpResponse(json.dumps(data_dict))@csrf_exempt
def task_add(request):print(request.POST)data_dict = {"status":True}return HttpResponse(json.dumps(data_dict))
效果:
在上述的基础上,我们进行保存数据以及数据校验。
③数据保存及校验
1.修改task.py
task.py
import jsonfrom django import forms
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from api.utils.form import BootStrapModelForm
from api.models import Taskclass TaskModelForm(BootStrapModelForm):class Meta:model = Taskfields = "__all__"widgets = {"detail": forms.TextInput,}@csrf_exempt
def task_list(request):form = TaskModelForm()return render(request, "task_list.html", {"form": form})@csrf_exempt
def task_ajax(request):print("get请求:", request.GET)print("POST请求", request.POST)data_dict = {"status": True, 'data': [11, 22, 33, 44]}return HttpResponse(json.dumps(data_dict))@csrf_exempt
def task_add(request):print(request.POST)# 采用ModelForm对用户发过来的数据进行校验form = TaskModelForm(data=request.POST)if form.is_valid():form.save()data_dict = {"status": True}return HttpResponse(json.dumps(data_dict))data_dict = {"status": False, "error": form.errors}return HttpResponse(json.dumps(data_dict))
2.修改task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading">表单</div><div class="panel-body"><form method="post" id="task_form" novalidate><div>{% for item in form %}<div class="col-xs-6"><div class="form-group" style="position: relative; margin-top: 20px"><label>{{ item.label }}</label>{{ item }}<span class="error_msg" style="color: red;position: absolute;"></span></div></div>{% endfor %}</div></form><div class="col-xs-12" style="margin-top: 20px"><input id="submit" type="submit" value="提 交" class="btn btn-primary center-block" style="width: 100px;"></div></div></div><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" value="点击1" class="btn btn-primary"><h3>示例2</h3><input type="text" id="txtuser" placeholder="姓名"><input type="text" id="txtpwd" placeholder="密码"><input id="btn2" type="button" value="点击2" class="btn btn-primary"><form id="from3"><h3>示例2</h3><input type="text" name="user" placeholder="姓名"><input type="text" name="age" placeholder="年龄"><input type="text" name="pwd" placeholder="密码"><input type="text" name="mobile" placeholder="电话"></form><input id="btn3" type="button" value="点击3" class="btn btn-primary"></div>{% endblock %}{% block script %}
<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();bindBtn3Event();bindaddEvent();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn3Event() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindaddEvent() {$("#submit").click(function () {// 每次点击,将以前的错误信息清空$(".error_msg").empty();$.ajax({url: '/task/add/',type: "post",data: $("#task_form").serialize(),dataType: "JSON",success: function (res) {// 如果校验正确,则输出“添加成功”if(res.status){alert("添加成功");} else {// 反之,则在输入框下显示错误信息$.each(res.error, function(name,data){$("#id_" + name).next().text(data[0]);})}}})})}
</script>
{% endblock %}
效果:
关于在输入框下显示错误的原因:
错误信息显示在输入框下是**因为代码通过 jQuery 的 next()
方法选择了输入框的下一个同级元素,并使用 text()
方法设置了该元素的文本内容。**这里假设每个输入框后都紧跟着一个用于显示错误信息的元素(例如一个 或
例如:
<!-- HTML 结构 -->
<input type="text" id="id_username">
<span class="error-message"></span><script>
// JavaScript 代码
$(document).ready(function() {var res = {status: false,error: {username: ["用户名已存在"]}};if (res.status) {alert("添加成功");} else {$.each(res.error, function(name, data) {$("#id_" + name).next(".error-message").text(data[0]);});}
});
</script>
在这个示例中,如果 res.status
为 false
,则会遍历 res.error 对象,并使用输入框的 id
(例如 "id_username"
)来定位相应的输入框。然后,通过调用 next(“.error-message”)选择紧跟在输入框后的 .error-message
类的元素,并使用 text(data[0])
设置其文本内容为错误信息(例如 "用户名已存在"
)。这样,错误信息就会显示在对应的输入框下方。
之后在上面HTML代码的基础上进行添加以下功能,具体包括:
- 添加数据后列表自动刷新
- 分页
- 搜索
4.再次修改task_list.html,以实现添加数据后列表自动刷新。
task_list.html
success: function (res) {// 如果校验正确,则输出“添加成功”if(res.status){alert("添加成功");// 页面刷新location.reload()} else {// 反之,则在输入框下显示错误信息$.each(res.error, function(name,data){$("#id_" + name).next().text(data[0]);})}}
5.继续修改task_list.html,在系统中实现并显示分页与搜索。
task_list.html
{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading">表单</div><div class="panel-body"><form method="post" id="task_form" novalidate><div>{% for item in form %}<div class="col-xs-6"><div class="form-group" style="position: relative; margin-top: 20px"><label>{{ item.label }}</label>{{ item }}<span class="error_msg" style="color: red;position: absolute;"></span></div></div>{% endfor %}</div></form><div class="col-xs-12" style="margin-top: 20px"><input id="submit" type="submit" value="提 交" class="btn btn-primary center-block"style="width: 100px;"></div></div></div><div><div class="panel panel-default"><!-- Default panel contents --><div class="panel-heading"><span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span><span>任务列表</span></div><!-- Table --><table class="table table-bordered"><thead><tr><th>ID</th><th>标题</th><th>级别</th><th>负责人</th><th>操作</th></tr></thead><tbody>{% for obj in queryset %}<tr><th>{{ obj.id }}</th><td>{{ obj.title }}</td><td>{{ obj.get_level_display }}</td><td>{{ obj.user.username }}</td><td><a class="btn btn-primary btn-xs" href="#">编辑</a><a class="btn btn-danger btn-xs" href="#">删除</a></td></tr>{% endfor %}</tbody></table></div></div><ul class="pagination">{{ page_string }}</ul><br><form method="get"><div style="display:inline-block; width: 150px;"><div class="input-group"><span> <input type="text" class="form-control" placeholder="请输入页码" name="page"></span><span class="input-group-btn"><button class="btn btn-primary" type="submit">跳转</button></span></div></div></form>{# <h1>任务管理</h1>#}
{# <h3>示例1</h3>#}
{# <input id="btn1" type="button" value="点击1" class="btn btn-primary">#}
{##}
{# <h3>示例2</h3>#}
{# <input type="text" id="txtuser" placeholder="姓名">#}
{# <input type="text" id="txtpwd" placeholder="密码">#}
{# <input id="btn2" type="button" value="点击2" class="btn btn-primary">#}
{##}
{# <form id="from3">#}
{# <h3>示例2</h3>#}
{# <input type="text" name="user" placeholder="姓名">#}
{# <input type="text" name="age" placeholder="年龄">#}
{# <input type="text" name="pwd" placeholder="密码">#}
{# <input type="text" name="mobile" placeholder="电话">#}
{# </form>#}
{# <input id="btn3" type="button" value="点击3" class="btn btn-primary">#}</div>{% endblock %}{% block script %}<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event();bindBtn2Event();bindBtn3Event();bindaddEvent();})function bindBtn1Event() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn2Event() {$("#btn2").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {name: $("#txtuser").val(),password: $("#txtpwd").val()},dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindBtn3Event() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(),dataType: "JSON",success: function (res) {console.log(res);console.log(res.status);console.log(res.data);}})})}function bindaddEvent() {$("#submit").click(function () {// 每次点击,将以前的错误信息清空$(".error_msg").empty();$.ajax({url: '/task/add/',type: "post",data: $("#task_form").serialize(),dataType: "JSON",success: function (res) {// 如果校验正确,则输出“添加成功”if (res.status) {alert("添加成功");// 页面刷新location.reload()} else {// 反之,则在输入框下显示错误信息$.each(res.error, function (name, data) {$("#id_" + name).next().text(data[0]);})}}})})}</script>
{% endblock %}
6.修改task.py
task.py
import json
from api.utils.pagination import Pagination
from django import forms
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from api.utils.form import BootStrapModelForm
from api.models import Taskclass TaskModelForm(BootStrapModelForm):class Meta:model = Taskfields = "__all__"widgets = {"detail": forms.TextInput,}@csrf_exempt
def task_list(request):form = TaskModelForm()return render(request, "task_list.html", {"form": form})@csrf_exempt
def task_ajax(request):print("get请求:", request.GET)print("POST请求", request.POST)data_dict = {"status": True, 'data': [11, 22, 33, 44]}return HttpResponse(json.dumps(data_dict))@csrf_exempt
def task_add(request):print(request.POST)# 采用ModelForm对用户发过来的数据进行校验form = TaskModelForm(data=request.POST)if form.is_valid():form.save()data_dict = {"status": True}return HttpResponse(json.dumps(data_dict))data_dict = {"status": False, "error": form.errors}return HttpResponse(json.dumps(data_dict))@csrf_exempt
def task_list(request):""" 任务列表 """form = TaskModelForm()# 生成页码与搜索data_dict = {}search_data = request.GET.get('query', "")# title__ccontains 表示使用title作为搜索字段进行内容匹配if search_data:data_dict["title__contains"] = search_data# 对搜索内容进行查询,为空表示获取所有数据queryset = Task.objects.filter(**data_dict).order_by('-id')page_object = Pagination(request, queryset, page_size=10, page_param="page")page_queryset = page_object.page_queryset# 调用对象的html方法,生成页码page_object.html()page_string = page_object.page_stringcontext = {"queryset": page_queryset,"form": form,"page_string": page_string,"search_data": search_data,}return render(request, "task_list.html", context)
效果:
本篇内容关于任务管理就暂时讲到这里,下一篇将会一起实现订单管理的内容,使系统的功能更加丰富,
很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!
相关文章:

Python Web开发记录 Day13:Django part7 Ajax入门与案例(任务管理)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 1、Ajax入门①简介②工作原理③优点④缺点⑤使用…...

寻找可能认识的人
给一个命名为:friend.txt的文件 其中每一行中给出两个名字,中间用空格分开。(下图为文件内容) 题目:《查找出可能认识的人 》 代码如下: RelationMapper: package com.fesco.friend;import or…...
机器学习----特征缩放
目录 一、什么是特征缩放: 二、为什么要进行特征缩放? 三、如何进行特征缩放: 1、归一化: 2、均值归一化: 3、标准化(数据需要符合正态分布): 一、什么是特征缩放: 通…...

机器学习_正则化
文章目录 代价函数 如果我们有非常多的特征,我们通过学习得到的假设可能能够非常好地适应训练集(代价函数可能几乎为 0),但是可能会不能推广到新的数据。 下图是一个回归问题的例子: 第一个模型是一个线性模型…...

python知识点总结(四)
这里写目录标题 1、Django 中的缓存是怎么用的?2、现有2元、3元、5元共三种面额的货币,如果需要找零99元,一共有多少种找零的方式?3、代码执行结果4、下面的代码执行结果为:5、说一下Python中变量的作用域。6、闭包7、python2与p…...

upload-labs-pass01
1.安装好环境进入关卡(记得打开小皮) 2.可以看到第一关是要求上传图片,但是同时限制了图片类型,那么如果我们将木马写入图片,但是类型又不在白名单,就要想办法绕过 3.可以看到这里的要求是有checkÿ…...
2.4 ROC曲线是什么?
2.4 ROC曲线是什么? 场景描述 二值分类器(Binary Classifier)是机器学习领域中最常见也是应用最广泛的分类器。 评价二值分类器的指标很多,比如precision、recall、F1score、P-R 曲线等。前面已对这些指标做了一定的介绍,但也发现这些指标或…...
mysql笔记:21. 演示脏读、不可重复读和幻读现象
文章目录 脏读1. 设置窗口B中事务的隔离级别2. 演示脏读3. 重新设置窗口B中事务的隔离级别4. 再次验证脏读 不可重复读1. 演示不可重复读2. 设置窗口B中事务的隔离级别3. 再次验证不可重复读 幻读1. 设置窗口B中事务的隔离级别2. 演示幻读3. 重新设置窗口B中事务的隔离级别4. 再…...

iOS通过wifi连接硬件设备
一、连接智能硬件设备的方式 连接智能硬件设备通常涉及到使用不同的通信技术和协议,例如 Bluetooth、Wi-Fi、Zigbee 等。下面我将详细介绍几种连接智能硬件设备的方式,并举例说明: 1.1 使用 Bluetooth 连接 方式: 通过使用 Cor…...

SQL-Labs靶场“36-37”关通关教程
一、36关 GET单引号宽字节注入 请求方式注入类型拼接方式GET联合、报错、布尔盲注、延时盲注id‘$id’ 首先我们进行测试(使用?id1\,查看过滤后的回显) 这里可以看到对我们的注释符进行了注释以及单双引号进行测试会发现都是如此ÿ…...

RabbitMQ介绍及搭建
架构 RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件,使用erlang语言编写,依赖Erlang环境运行。 Broker:运行消息队列服务进程的节点,包含Exchange、Queue; Producer:消…...

VSCode + PicGo + Github 实现markdown图床管理
目录 PicGo客户端VSvode插件 PicGo客户端 PicGo 是一个图片上传管理工具 官网:https://molunerfinn.com/PicGo/ github图传使用说明:https://picgo.github.io/PicGo-Doc/zh/guide/config.html#GitHub图床 步骤: 1、创建一个github公开仓库…...

小程序搜索排名优化二三事
小程序的优化主要是排名优化和性能优化两个版块。性能优化这方面主要靠开发者自己完善,我们团队提供的服务就是把产品的排名打上去,获得更多的自然流量,实现盈利。 如何提升小程序的搜索排名主要从如下几个方面出发: 首先要知道…...
分布式 Session--一起学习吧之架构
一、定义 分布式Session是指在一个分布式系统中,多个服务器之间共享用户的会话信息。在Web应用中,Session通常用于跟踪用户的状态和会话数据。然而,在分布式系统中,由于用户请求可能被分发到不同的服务器上,因此需要一…...
记录一下小程序自定义导航栏消息未读已读小红点,以及分组件的消息数量数据实时读取
本案例,Message 身为组件,使用不了任何钩子来重新获取 this.getMessageList() 消息列表 使用 props 父子传参,因为 Message 组件使用不了页面生命周期从而无法拿到传递过来的数据 使用 watch 监听不到 props 更不建议使用本地存储,…...

qt+ffmpeg 实现音视频播放(二)之音频播放
一、音频播放流程 1、打开音频文件 通过 avformat_open_input() 打开媒体文件并分配和初始化 AVFormatContext 结构体。 函数原型如下: int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); 参数说…...
Bash Shell中双引号中的感叹号问题详解
Bash Shell中双引号中的感叹号问题详解 在Bash Shell中,感叹号(!)是一个特殊字符,主要用于历史扩展。历史扩展允许你使用!来引用历史命令。然而,当你在双引号中使用感叹号时,如果你在双引号中直接使用感叹号,它可能会…...
MFC中CString的用法及使用示例
CString 是 Microsoft Foundation Classes (MFC) 库中的一个类,用于处理 C 风格的字符串。它提供了很多有用的方法和函数,使得字符串的操作变得更加简单和安全。下面是一些 CString 的基本用法和使用示例: 1. 包含头文件 首先,你…...

注册个人小程序
访问地址 https://mp.weixin.qq.com/ 立即注册 选择小程序 注册 填写信息 登录邮箱 访问邮箱的链接激活账号 选择个人,填写信息 注册完成,即可登录进入填写信息...
VTK----VTK的事件机制
事件的发送和接收对于一个应用或系统来说是一个基本的功能,所以一些通用的库对应地也建立了自己的一套管理事件的机制,例如QT、VTK都有自己的事件管理机制。VTK库中定义了很多的事件,这些事件是如何进行管理的,下面从三个方面来详细的说明。 1 事件的管理 在讲述VTK的事件…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...

2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...

算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...