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的工作原理基于以下几个关键技术:

  1. XMLHttpRequest对象(XHR):负责与服务器异步交换数据。通过这个对象发送请求并接收响应,开发者可以在不重新加载页面的情况下更新网页的某一部分。
  2. JavaScript/DOM:用于动态显示和交互。
  3. CSS:用于定义数据的样式。
  4. XML:曾经是数据交换的主要格式,但现在JSON格式因为其轻量和易于解析的特性,已经成为更受欢迎的数据交换格式。
③优点
  1. 提高用户体验:通过局部刷新页面内容,减少等待时间和服务器响应时间,从而提高用户体验。
  2. 减轻服务器负担:仅请求必要的数据,而不是整个页面的数据,减少了带宽的使用和服务器的负担。
  3. 支持异步通信:页面可以在等待服务器响应的同时,继续处理其他事务,提高了应用程序的效率。
④缺点
  1. SEO问题:由于AJAX加载的内容可能不会被搜索引擎爬虫抓取,因此可能影响页面的SEO。
  2. 兼容性问题:虽然现代浏览器都支持AJAX,但在一些旧浏览器中可能存在兼容性问题。
  3. 安全问题:由于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和表单的形式提交的两种请求方法,GETPOST,它们是两种常用的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 %}

效果:

image-20240317122518852

按F12打开调试页面,可以看到"成功了"。

image-20240317111512230

④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 %}

效果:

image-20240317123407974

后台输出:

image-20240317123540592

优化上面的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))

效果:

image-20240317125748102

到了,这里可能会有疑问,json数据?什么是json?

②补充:json

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。JSON格式是独立于语言的,尽管它是由JavaScript的对象字面量语法派生而来的,但是JSON格式的数据可以由多种语言读取,如Python、Ruby、PHP等。

1.JSON的结构

JSON格式支持两种结构:

  • 键/值对集合:在各种语言中,这被实现为对象、记录、结构、字典、哈希表、有键列表,或者关联数组。
  • 有序的值列表:在大多数语言中,这被实现为数组、向量、列表或序列。

JSON的基本类型包括数字(整数或浮点数)、字符串(在双引号中)、布尔值(truefalse)、数组(在方括号中)、对象(在大括号中的键/值对)和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 %}

效果:

image-20240317154142949

image-20240317154128819

这样是实现了,但是如果前端代码过多的话,又该怎么办呢?此时我们就需要用更简单的方法来进行批量处理了。

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 %}

效果:

image-20240317160912672

image-20240317160931274

至此,如何在浏览器不刷新的情况下,向后台提交数据的问题也就解决了。

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表已经添加完成。

image-20240317184004261

启动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 %}

image-20240317185646313

其实到这里 ,虽然界面已经出来了,但是这个界面占整个页面的篇幅太大了,因此我们要优化一下前端的展示页面,以使整体更加和谐。

4.修改task_list.html

注意,下面前端代码里的button必须放在form表单外,否则submit的ajax触发机制不会生效。

原因如下:

在HTML中,如果将button标签放置在form标签内部,并且没有指定type属性或将type属性设为submit,当按钮被点击时,默认触发表单的提交。如果你希望使用button进行AJAX操作而不提交表单,你有两种选择:

  1. button标签放置在form标签之外。
  2. form标签内部使用button标签,但要将buttontype属性设置为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 %}

效果:

image-20240317220222056

②任务添加(二)

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))

效果:

image-20240317223607373

image-20240317223619958

在上述的基础上,我们进行保存数据以及数据校验。

③数据保存及校验

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 %}

效果:

image-20240317230012622

关于在输入框下显示错误的原因:

错误信息显示在输入框下是**因为代码通过 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.statusfalse,则会遍历 res.error 对象,并使用输入框的 id(例如 "id_username")来定位相应的输入框。然后,通过调用 next(“.error-message”)选择紧跟在输入框后的 .error-message 类的元素,并使用 text(data[0]) 设置其文本内容为错误信息(例如 "用户名已存在")。这样,错误信息就会显示在对应的输入框下方。

之后在上面HTML代码的基础上进行添加以下功能,具体包括:

  • 添加数据后列表自动刷新
  • 分页
  • 搜索

4.再次修改task_list.html,以实现添加数据后列表自动刷新。

image-20240317230325254

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)

效果:

128

本篇内容关于任务管理就暂时讲到这里,下一篇将会一起实现订单管理的内容,使系统的功能更加丰富,

很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

upload-labs-pass01

1.安装好环境进入关卡&#xff08;记得打开小皮&#xff09; 2.可以看到第一关是要求上传图片&#xff0c;但是同时限制了图片类型&#xff0c;那么如果我们将木马写入图片&#xff0c;但是类型又不在白名单&#xff0c;就要想办法绕过 3.可以看到这里的要求是有check&#xff…

中国银行信息系统应用架构发展历程

概述&#xff1a; 从 20 世纪 80 年代开始至今&#xff0c;我国银行业信息化历程已 有四十年历史。虽然相对于发达国家来讲&#xff0c;我国银行业务信 息化起步较晚&#xff0c;但发展速度很快&#xff0c; 目前我国一些大型商业银行的信息化程度已经处于全球领先水平。 “银行…

web渗透测试漏洞复现:Elasticsearch未授权漏洞复现

web渗透测试漏洞复现 Elasticsearch未授权漏洞复现Elasticsearch简介Elasticsearch复现Elasticsearch漏洞修复和加固措施 Elasticsearch未授权漏洞复现 Elasticsearch简介 Elasticsearch 是一款 Java 编写的企业级搜索服务&#xff0c;它以分布式多用户能力和全文搜索引擎为特…

Vue3学习日记 Day4 —— pnpm,Eslint

注&#xff1a;此课程需要有Git的基础才能学习 一、pnpm包管理工具 1、使用原因 1.1、速度快&#xff0c;远胜过yarn和npm 1.2、节省磁盘空间 2、使用方式 2.1、安装方式 npm install -g pnpm 2.2、创建项目 pnpm create vue 二、Eslint配置代码风格 1、环境同步 1、禁用Pret…

webpack5零基础入门-11处理html资源

1.目的 主要是为了自动引入打包后的js与css资源&#xff0c;避免手动引入 2.安装相关包 npm install --save-dev html-webpack-plugin 3.引入插件 const HtmlWebpackPlugin require(html-webpack-plugin); 4.添加插件&#xff08;通过new方法调用&#xff09; /**插件 *…

外贸网站文章批量生成器

随着全球贸易的不断发展&#xff0c;越来越多的企业开始关注外贸市场&#xff0c;而拥有高质量的内容是吸引潜在客户的关键之一。然而&#xff0c;为外贸网站生产大量优质的文章内容可能是一项耗时且繁琐的任务。因此&#xff0c;外贸网站文章批量生成软件成为了解决这一难题的…

【Spring MVC】Spring MVC拦截器(Interceptor)

目录 一、拦截器介绍 二、拦截器 Interceptor 定义 2.1 HandlerInterceptor接口 2.2 Spring MVC中提供的一些HandlerInterceptor接口实现类 1、AsyncHandlerInterceptor 2、WebRequestInterceptor 3、MappedInterceptor 4、ConversionServiceExposingInterceptor 三、拦…

研究人员发现 OpenAI ChatGPT、Google Gemini 的漏洞

自 OpenAI 推出 ChatGPT 以来&#xff0c;生成式 AI 聊天机器人的数量及其在企业中的采用率在一年多时间里呈爆炸式增长&#xff0c;但网络安全专业人士的担忧也随之增加&#xff0c;他们不仅担心威胁组织对新兴技术的使用&#xff0c;还担心大型网络的安全性及模型&#xff08…

Chrome历史版本下载地址:Google Chrome Older Versions Download (Windows, Linux Mac)

最近升级到最新版本Chrome后发现页面居然显示错乱,是在无语, 打算退回原来的版本, 又发现官方只提供最新的版本下载, 为了解决这个问题所有收集了Chrome历史版本的下载地址分享给大家. Google Chrome Windows version 32-bit VersionSizeDate104.0.5112.10279.68 MB2022-05-30…

【小迪安全】学习cho1

介绍了一些名词&#xff1a; POC、EXP、Payload与Shellcode nc -lvvp 端口号 监听服务器端口 个人用机使用最多的是&#xff1a;windows10 服务器用机使用最多的是&#xff1a;Windows8&#xff0c;12&#xff0c;16 流量被防火墙拦截了&#xff0c;到这里进行给与权限 文件…

【CNN轻量化】RepViT: Revisiting Mobile CNN From ViT Perspective

RepViT: Revisiting Mobile CNN From ViT Perspective 论文链接&#xff1a;https://arxiv.org/abs/2307.09283 代码链接&#xff1a;https://github.com/THU-MIG/RepViT 一、摘要 探究了许多轻量级ViTs和轻量级CNNs之间的结构联系。文中从ViT的视角重新审视轻量级CNNs的高效…

Java 中的泛型(两万字超全详解)

文章目录 前言一、泛型概述1. 什么是泛型&#xff1f;为什么要使用泛型&#xff1f;2. 泛型使用场景3. 泛型概述小结 二、泛型类1. 泛型类的定义2. 泛型类的使用 三、泛型接口四、泛型方法1. 泛型方法的定义2. 泛型方法的使用3. 泛型方法中的类型推断 五、类型擦除1. 什么是类型…

本地虚拟机平台Proxmox VE结合Cpolar内网穿透实现公网远程访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

扇区架次数动态展示

打开前端Vue项目&#xff1a;kongguan_web&#xff0c;完成前端src/components/echart/SectorFlightChart.vue页面设计&#xff0c;使用ECharts插件实现柱状图和饼状图 在src/components目录下创建echart目录&#xff0c;完成src/components/echart/SectorFlightChart.vue 的页…

C++开发基础——类对象与构造析构

一、基础概念 类&#xff1a;用户自定义的数据类型。 对象&#xff1a;类类型的变量&#xff0c;类的实例。 类的成员&#xff1a;成员变量和成员函数。 成员变量&#xff1a;类中定义的变量。 成员函数&#xff1a;类中定义的函数。 定义类的代码样例&#xff1a; class…

嵌入式学习第二十九天!(数据结构的概念、单向链表)

数据结构&#xff1a; 1. 定义&#xff1a; 一组用来保存一种或者多种特定关系的数据的集合&#xff08;组织和存储数据&#xff09; 1. 程序设计&#xff1a; 将现实中大量而复杂的问题以特定的数据类型和特定的数据结构存储在内存中&#xff0c;并在此基础上实现某个特定的功…

【排序】快速排序

原理 对于一个数组x&#xff0c;快速排序流程如下&#xff1a; 确定分界点a&#xff0c;可以取x[l]、x[r]、x[l r / 2]、随机&#xff08;四种都可以&#xff09;调整区间&#xff0c;使得&#xff1a;区间被分成 < a 和 > a的两部分&#xff0c;左边 < a&#xff…

Jenkins-pipeline流水线构建完钉钉通知

添加钉钉机器人 在钉钉群设置里添加机器人拿出Webhook地址&#xff0c;设置关键词 Jenkins安装钉钉插件 Dashboard > 系统管理 > 插件管理&#xff0c;搜索构建通知&#xff0c;直接搜索Ding Talk也行 安装DingTalk插件&#xff0c;重启Jenkins 来到Dashboard > 系…

【物联网应用】基于云计算的智能化温室种植一体化平台

目录 第一章 作品概述 1.1. 作品名称 1.2. 应用领域 1.3.主要功能 1.4.创新性说明 第二章 需求分析 2.1 现实背景 2.2 用户群体及系统功能 2.3 竞品分析 第三章 技术方案 3.1. 硬件组成与来源 3.2. 硬件设计合理性 3.3. 硬件系统设计图 3.4. 接口的通用性与可扩展性 3.5. 代码规…

【ARM】DSTREAM上面的各个指示灯代表什么意思?

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 对于DStream仿真器上面的指示灯亮灭代表的意义进行分析。 2、 问题场景 主要对于DStream仿真器的使用过程中&#xff0c;不同的情况下面仿真器的指示灯会进行相应的亮灭。了解一下不同指示灯的亮灭所提示的信息…