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.hqwc.cn/news/549177.html

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

相关文章

【理解】Redis 中的事务及持久化方式

目录 相关传送门 1. Redis 中的事务 2. Redis 持久化 2.1 RDB 方式 2.1.1 RDB手动 2.1.2 RDB自动 2.2 AOF方式 2.2.1 AOF执行过程 2.2.2 AOF写数据的策略 2.2.3 AOF相关配置 2.2.4 AOF写数据遇到的问题 2.2.5 AOF重写 2.2.6 AOF重写规则 2.2.7 AOF重写方式 2.2.8…

java 面向对象--equals方法

Object 类的使用 类 java.lang.Object是类层次结构的根类&#xff0c;即所有其它类的父类。每个类都使用 Object 作为超类。 Object类型的变量与除Object以外的任意引用数据类型的对象都存在多态引用 method(Object obj){…} //可以接收任何类作为其参数 Person o new Person…

数据驱动校园管理:山海鲸可视化软件看板搭建记

随着信息化时代的到来&#xff0c;校园管理也逐渐向数字化、可视化转型。作为一名数据分析师&#xff0c;我有幸参与了使用山海鲸可视化软件搭建校园管理可视化看板的项目&#xff0c;山海鲸可视化软件是近些年新崛起的一款可视化产品&#xff0c;支持免费可视化编辑、私有化部…

蓝桥杯物联网竞赛_STM32L071_12_按键中断与串口中断

按键中断&#xff1a; 将按键配置成GPIO_EXTI中断即外部中断 模式有三种上升沿&#xff0c;下降沿&#xff0c;上升沿和下降沿都会中断 external -> 外部的 interrupt -> 打断 trigger -> 触发 detection -> 探测 NVIC中将中断线ENABLE 找接口函数 在接口函数中写…

【边缘智能】Jetson板卡上安装QT5与OpenCV集成

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; 安装QT5与QT Creator 如果只是简单的使用QT的GUI库&#xff0c;没有其它要求&#xff0c;其实特别容易&#xff0c;一行命令行…

Flutter-底部弹出框(Widget层级)

需求 支持底部弹出对话框。支持手势滑动关闭。支持在widget中嵌入引用。支持底部弹出框弹出后不影响其他操作。支持弹出框中内容固定头部和下面列表时&#xff0c;支持触摸头部并在列表不在头部的时候支持滑动关闭 简述 通过上面的需求可知&#xff0c;就是在界面中可以支持…

最细致最简单的 Arm 架构搭建 Harbor

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; ARM离线版本安装 官方提供了一个 arm 版本&#xff0c;但是好久都没更新了&#xff0c;地址&#xff1a;https://github.com/goharbor/harbor-arm 。 也不知道为什么不更新&#xff0c;我看…

CTF题型 SSTI(1) Flask-SSTI-labs 通关 题记

CTF题型 SSTI(1) Flask-SSTI-labs 通关 题记 文章目录 CTF题型 SSTI(1) Flask-SSTI-labs 通关 题记前记获取键值或下标的方式获取属性的方式 Level 1 no wafLevel 2 bl[\{\{]Level 3 no waf and blindLevel 4 bl[[, ]]获取键值或下标 Level 5 bl[\, "]Level 6 bl[_]Level …

Redis 过期删除策略和内存淘汰策略有什么区别?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) Redis 的「内存淘汰策略」和「过期删除策略」&#xff0c;很多小伙伴容易混淆&#xff0c;这两个机制虽然都是做删除的操作&#xff0c;但是触发的条件和使用的策略都是不同的。 今天就跟大家理一理&…

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; /**插件 *…

【AAAI 2024】MuLTI:高效视频与语言理解

一、背景 1.1 多模态的发展 多模态理解模型具有广泛的应用&#xff0c;比如多标签分类&#xff08;Classification&#xff09;、视频问答&#xff08;videoQA&#xff09;和文本视频检索&#xff08;Retrieval&#xff09;等。现有的方法已经在视频和语言理解方面取得了重大…

从零开始学习深度学习库-4:自动微分

欢迎来到本系列的第四部分&#xff0c;在这里我们将讨论自动微分 介绍 自动微分&#xff08;Automatic Differentiation&#xff0c;简称AD&#xff09;是一种计算数学函数导数&#xff08;梯度&#xff09;的技术。在深度学习和其他领域中&#xff0c;自动微分是一种极其重要…