Django 调用AJAX编程

Django 调用AJAX编程

AJAX的意思是异步的JavaScript和XML,也就是用JavaScript与服务器进行异步交互,传输的数据为XML,实际上现在传输的数据大多是JSON格式的。AJAX最大的优点是在不重新加载整个页面的情况下,可以与后端服务器交换数据并更新部分网页内容。Web开发需要经常调用AJAX进行业务功能开发。

AJAX基本知识

JSON基本知识

AJAX交换数据类型用得最多的是JSON数据格式。

python提供了一个json模块,主要有4个函数:

  • json.dumps()把一个字典对象转换为JSON字符串。

    import json
    person = {
        'name':'zhangsan',
        'age':18,
    }
    json_str = json.dumps(person)
    # 结果是{"name":"zhangsan","age":18}
    

    json.dumps()函数有一个可选参数是ensure_ascii,默认为True,保证转换后的JSON字符串中全部是ASCII字符,非ASCII字符都会被转义。如果数据中存在中文或其他非ASCII字符,最好将其设为False,保证输出结果正常。

    import json
    person = {
        '姓名':'张三',
        '年龄':18,
    }
    json_str1 = json.dumps(person) # 结果为{"\u59d3\u540d":"\u5f20\u4e09","\u5e74\u9f84":18}
    json_str2 = json.dumps(person,ensure_ascii=False) # 结果为{"姓名":"张三","年龄":18}
    
  • json.loads()将JSON字符串转换为字典。

    import json
    str = '{"name":"Tom","age":18}'
    dic = json.loads(str)
    
  • json.dump()将一个python字典转换为JSON格式并写入文件。

    import json
    person = {
        'name':'zhangsan',
        'age':18,
    }
    with open('person.txt','w') as f:
        json.dump(person,f)
    
  • json.load()将一个python文件中的内容转换成python字典。

    with open('person.txt','r') as f:
        person = json.load(f)
    

JavaScript中:

  • JSON.parse()将字符串转换为对象:

    var Object = JSON.parse(jsonstr);
    
  • JSON.stringify()将对象转换为字符串:

    var jsonstr = JSON.stringify(jsonObject)
    

AJAX简单使用

命令行新建test_ajax应用,settings中加入。在/test_orm/test_orm/urls中加入一条配置:path('test_ajax/',include('test_ajax.urls')),

在/test_orm/test_ajax下新建urls:

from django.urls import path
from . import views
urlpatterns = [
    # 显示唐诗页面
    path('tangshi/',views.tangshi),
    # 补全唐诗
    path('tangshi_ret/',views.tangshi_ret),
    # 唐诗配图
    path('tangshi_img/',views.tangshi_img),
]

views中编写视图函数:

from django.shortcuts import render,HttpResponse
from . import models
from . import forms
import json
# 打开模板文件
def tangshi(request):
    return render(request,'test_ajax/tangshi.html')
# 生成一个字典并转换为JSON字符串,然后返回响应
def tangshi_ret(request):
    ts1 = request.GET.get('ts1')
    ts2 = request.GET.get('ts2')
    if ts1 == '床前明月光':
        ts3 = '举头望明月'
        ts4 = '低头思故乡'
        dic = {'ts3':ts3,'ts4':ts4}
        data_ret = json.dumps(dic)
        return HttpResponse(data_ret)
# 返回包含图片地址字符串的响应
def tangshi_img(request):
    src = '/media/month.jpg'
    return HttpResponse(src)

tangshi.html:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>AJAX测试</title>
</head>
<body>
<div align="center">

    <br>
    <label>静夜思</label>
    <hr>
    <div><input type="text" id="ts1" value="床前明月光"></div>
    <div><input type="text" id="ts2" value="疑是地上霜"></div>
    <div><input type="button" id="btn1" value="补全唐诗"></div>
    <div><input type="text" id="ts3"></div>
    <div><input type="text" id="ts4"></div>
    <div><input type="button" id="btn2" value="诗配图"></div>
    <br>
    <div id="img"></div>

</div>
<script src="{% static 'jquery-3.4.1.min.js' %}"></script>
<script>
  $("#btn1").on("click", function () {
    //
      var ts1 = $("#ts1").val();
      var ts2 = $("#ts2").val();
      // 往后端发数据
      $.ajax({
          url: "/test_ajax/tangshi_ret/",
          type: "get",
          data: {"ts1": ts1, "ts2": ts2},
          success: function (arg) {

              data=JSON.parse(arg)
              $("#ts3").val(data['ts3']);
               $("#ts4").val(data['ts4']);
          }
      })
  });

   $("#btn2").on("click", function () {
        $.ajax({
            url: "/test_ajax/tangshi_img/",
            type: "get",
            success:function (imgsrc) {

                // 在页面上创建一个标签
                 var img = document.createElement("img");
                 img.src = imgsrc;

                // 把创建的img标签添加到文档中
                $("#img").after(img);
                $("#btn2").attr("disabled",true)
            }
        })
    })

</script>
</body>
</html>

说明:

首先介绍一下JQuery的AJAX用法,主要是在$.ajax()中加入参数、方法。

  • url:String类型的参数,表示向这个地址发送请求,默认为当前页的地址。
  • type:String类型的参数,请求方式主要是POST、GET,默认是GET。
  • async:布尔类型,默认为true,所有请求均为异步请求。要发送同步请求需设为false。
  • data:String或其他类型,发送到服务器的数据。如果不是字符串自动转换为字符串格式。
  • success:Function类型的参数,是请求成功后调用的回调函数。有两个参数,一个是服务器发回的数据,另一个是包含成功代码的字符串。
  • error:Function类型的参数,是请求失败时被调用的回调函数。有三个参数,即XMLHttpRequest对象、错误信息、捕获的错误对象。

按钮补全唐诗的onclick事件中调用了AJAX。代码写法固定,主要设置了url、type、data、success,url的值与URL配置项相对应,根据url的值可以推导出AJAX向视图函数tangshi_ret发送的请求、提交的数据。由于视图函数返回的数据转换成了JSON字符串,所以在success指定的函数中通过data=JSON.parse(arg)语句把字符串转换回字典类型。

样例9:AJAX应用开发

本节开发一个简单样例以实现记录删除、增加、注册校验等功能,这些功能是在Web开发中经常用到的。

URL配置

在test_ajax的urls中加入:

from django.urls import  path
from . import views
urlpatterns = [
    # 员工列表
    path('list_person/',views.list_person),
    # 删除员工
    path('del_row/',views.del_row),
    # 增加员工
    path('add_person/',views.add_person),
    # 注册时进行姓名校验
    path('test_name/',views.test_name),
    ]

数据模型

from django.db import models

class person(models.Model):#员工数据模型(员工数据表)
    name=models.CharField(max_length=32,verbose_name='姓名') #员工姓名
    email=models.EmailField(verbose_name='邮箱')#员工的邮箱
    salary=models.DecimalField(max_digits=8,decimal_places=2)#薪水,数值型
    def __str__(self):
        return self.name

员工列表及记录删除

views中加入:

def list_person(request):
    per_list=models.person.objects.all()

    return render(request,'test_ajax/list_person.html',{'person_list':per_list})
def del_row(request):
        id = request.GET.get("id")
        models.person.objects.filter(id=id).delete()
        return HttpResponse("操作成功!")

list_person.html:

{% load static %}
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
    <title>模板样例</title>
    <!-- Bootstrap core CSS -->
    <link href="{% static 'bootstrap/css/bootstrap.min.css'%}" rel="stylesheet">
</head>
<body>
<div class="col-sm-4 col-sm-offset-4 col-md-6 col-md-offset-3 main">
    <br>
    <br>
    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">员工列表</h3> <!--这里加标题 //-->
        </div>
        <div class="panel-body"> <!--将表格放在这个<div class="panel-body">的标签中 //-->

            <table class="table table-bordered table-condensed table-striped table-hover"> <!--给表格增加bootstrap样式 //-->
                <thead>
                <tr>
                     <th>ID</th>
                    <th>姓名</th>
                    <th>邮件</th>
                    <th>薪水</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                {% for per in person_list %}
                <tr>
                    <td>{{ per.id }}</td>
                    <td>{{ per.name }}</td>
                    <td>{{ per.email }}</td>
                    <td>{{ per.salary }}</td>
                      <td><a  class="btn btn-danger delete"><i
                                    class="fa fa-trash-o fa-fw"
                                    aria-hidden="true"></i>&nbsp;删除</a>
                            </td>
                </tr>
                {% empty %}
                <tr>
                    <td colspan="7">无相关记录!</td>
                </tr>
                {% endfor %}
                </tbody>
            </table>


        </div>
    </div>
</div>
<script src="{% static 'jquery-3.4.1.min.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'sweetalert/sweetalert.min.css' %}">

 <script src="{% static 'sweetalert/sweetalert.min.js' %}"></script>
<!--<link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js"></script> //-->
<script>
    // 找到删除按钮绑定事件
    $(".delete").on("click", function () {
		//取得删除按钮所在行
         var $row = $(this).parent().parent();
         //alert($row)
        var Id = $row.children().eq(0).text();
        swal({
          //提示框的标题
          title: "是否真的要删除该记录?",
          //内容
          text: "正在删除id号为"+Id +"的记录",
          //图标样式
          type: "warning",
          //是否显示取消按钮
          showCancelButton: true,
          //设置确认按钮背景色为红色
          confirmButtonColor: '#d33',
          //设置确认按钮样式类
          confirmButtonClass: "btn btn-danger",
          //文本
          confirmButtonText: "确认",
          //取消按钮文本
          cancelButtonText: "取消",
          //单击确认后模态窗口仍然保留就设置就设置为false
          closeOnConfirm: false,
          //单击确认后模态窗口显示正在加载的图标
          showLoaderOnConfirm: true
        },
         //单击确认按钮后调用的函数
         function(){
            // 向后端发送删除的请求
            $.ajax({
                url: "/test_ajax/del_row/",
                type: "get",
                data: {"id":Id},
                success:function (arg) {
                    swal(arg, "删除成功!", "success");
                    $row.remove();
                }
            });

        });

    })
</script>
</body>
</html>

说明:

代码引用SweetAlert组件。模板文件通过Bootstrap表格把数据库表person中的记录列举出来,并在每一行记录后加了一个删除按钮,这个删除按钮的onclick时事件引起了SweetAlert组件,形式为swal({...})。showLoaderOnConfirm默认为false,当该参数为true时,单击确认按钮会显示正在加载的图标。常用的情形是当用户单击确认按钮后会提交AJAX,这时在AJAX提交的过程中会显示正在加载的图标。

员工信息增加

增加视图函数

from django.http import JsonResponse
def add_person(request):
    # 前端AJAX的提交方式是POST
    if request.method=='POST':
        # 初始化一个字典
        ret = {"status": 0, "url_or_msg": ""}
        # 用request.POST实例化person_form表单并赋值
        form_obj=forms.person_form(request.POST)
        print(form_obj)
        if form_obj.is_valid(): #表单数据校验
            person_obj=models.person.objects.create(
                name=form_obj.cleaned_data['name'],
                email=form_obj.cleaned_data['email'],
                salary=form_obj.cleaned_data['salary']
            ) #在数据库表中新增一条记录
            ret["url_or_msg"] = "/test_ajax/list_person/"
            return JsonResponse(ret)
        else:
            ret["status"] = 1
            ret["url_or_msg"] = form_obj.errors
            print(ret)
            return JsonResponse(ret)

    form_obj=forms.person_form() #第一次打开页面,初始化一个表单对象
    return render(request,'test_ajax/add_person.html',{'formobj':form_obj}) #定向到增加页面,并传递参数

# 校验用户名是否已被注册
def test_name(request):
    ret = {"status": 0, "message": ""}
    name = request.GET.get("name")
    per_obj = models.person.objects.filter(name=name)
    if per_obj:
        ret["status"] = 1
        ret["message"] = "用户名已存在,请重新录入!"
    return JsonResponse(ret)

说明:

视图函数add_person的主要逻辑是接收AJAX通过POST请求提交到后端的数据,并且赋值给person_form的实例化对象form_obj,同时在数据库表增加一条记录。

函数add_person通过JsonResponse函数向AJAX返回数据,这里对这个函数简单介绍,函数的形式如JsonResponse(data,safe=True,json_dumps_params=None)。

  • data:默认是字典类型,当data类型是list、tuple、set等类型时,safe设为false才不会报错。
  • safe:默认True,这时data必须是字典类型。
  • json_dumps_params:字典类型,默认为空值,设置json_dumps_params={'ensure_ascii':False}可以把含有中文的字典正常转换为JSON对象。

JsonResponse函数执行后,Content-Type默认设置为application/json,因此前端AJAX可直接使用该函数返回的对象,不需要类型转换。

person_form表单:

from django import forms
class person_form(forms.Form):
    id=forms.IntegerField(label='',widget=forms.widgets.NumberInput(attrs={'hidden':'true'}), required=False)
    name=forms.CharField(
        label='姓名',
        error_messages={
            "required": "字段不为为空",
            "invalid": "格式错误"
        },
        widget=forms.widgets.TextInput(attrs={'class':'form-control', "placeholder":"请输入姓名","autofocus":True}))

    email=forms.EmailField(
        label='邮箱',
        error_messages={
            "required": "字段不为为空",
            "invalid": "格式错误,请录入邮箱格式"
        },
        widget=forms.widgets.EmailInput(attrs={'class':'form-control', "placeholder":"请输入邮箱"}))

    salary=forms.DecimalField(
        label='薪金',
        error_messages={
            "required": "字段不为为空",
            "invalid": "格式错误,请录入数字"
        },
        widget=forms.widgets.NumberInput(attrs={'class':'form-control', "placeholder":"请输入薪金"}))

add_person.html:

{% load static %}
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Django Form样例</title>
    <!-- Bootstrap core CSS -->
    <link rel="icon" href="{% static 'favicon.ico' %}"  >
    <link href="{% static 'bootstrap/css/bootstrap.min.css'%}" rel="stylesheet">
    <link rel="stylesheet" href="{% static 'fontawesome/css/font-awesome.min.css'%}">
</head>

<body>
<div class="container">
    <div class="row">
        <div class="col-md-offset-3 col-md-6">
            <div class="page-header">
                <h1>Django Form及AJAX测试
                    <small>--增加</small>
                </h1>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">增加</h3> <!--这里加标题 //-->
                </div>
                <div class="panel-body">
                    <form action="/test_ajax/add_person/" method="post" class="form-horizontal " novalidate>
                        {% csrf_token %}
                        {{ formobj.id }}
                        <div class="form-group">
                            <label for="{{ formobj.name.id_for_label }}" class="col-md-2 control-label">
                                {{ formobj.name.label }}</label>
                            <div class="col-md-8">
                                {{ formobj.name }}
                                <span class="help-block">{{ formobj.name.errors.0 }}</span>
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="{{ formobj.email.id_for_label }}" class="col-md-2 control-label">
                                {{ formobj.email.label }}</label>
                            <div class="col-md-8">
                                {{ formobj.email }}
                                <span class="help-block">{{ formobj.email.errors.0 }}</span>
                            </div>
                        </div>
                        <div class="form-group">
                            <label for="{{ formobj.salary.id_for_label }}" class="col-md-2 control-label">
                                {{ formobj.salary.label }}</label>
                            <div class="col-md-8">
                                {{ formobj.salary }}
                                <span class="help-block">{{ formobj.salary.errors.0 }}</span>
                            </div>
                        </div>

                        <div align="center">
                            <!-- type='submit'会出错,请注意!!!  -->
                            <input type="button" class="btn btn-primary" value="增加" id="add_button">
                        </div>
                    </form>

                </div>
            </div>
        </div>
    </div>
</div>

<script src="{% static 'jquery-3.4.1.min.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js'%}"></script>
<script>
//当表单中input标签得到焦点
 $("form input").focus(function () {
     	//删去当前input标签后面的span标签中的文本——text("")
     	//并删去样式
        $(this).next("span").text("").parent().parent().removeClass("has-error");
    });
 // 单击增加按钮
    $("#add_button").click(function () {
        // 取到用户填写的注册数据,向后端发送AJAX请求
        // 先初始化一个FormData对象,这个对象可以保存表单中各字段的值
        var formData = new FormData();
        formData.append("name", $("#id_name").val());
        formData.append("email", $("#id_email").val());
        formData.append("salary", $("#id_salary").val());
        // 取得{% csrf_token %}的值,保存到formData对象,这一步必须做
        formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
        // AJAX提交注册的数据
        $.ajax({
            url: "/test_ajax/add_person/",
            type: "post",
            processData: false,  // 告诉jQuery不要处理我的数据
            contentType: false,  // 告诉jQuery不要设置content类型
            data: formData,
            success:function (data) {
                 if (data.status){
                    $.each(data.url_or_msg, function (k,v) {

                        //alert(v[0]+$('#id_name').next("span").text())
                        $("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
                    })
                }else {
                    // 没有错误就跳转到指定页面

                    location.href = data.url_or_msg;
                }
            }
        })
    });
// 输入姓名的文本框onblur事件
 $("#id_name").on("blur", function () {
        // 取到用户填写的值
        var name = $(this).val();
        // 发请求
        $.ajax({
            url: "/test_ajax/test_name/",
            type: "get",
            data: {"name": name},
            success: function (data) {
                if (data.status){
                    // 用户名已被注册
                    $("#id_name").next("span").text(data.message).parent().parent().addClass("has-error");
                }
            }
        })
    })


</script>
</body>
</html>

说明:

在增加按钮的onclick事件中调用AJAX向后端提交数据。由于数据来自表单,这里需要建立一个FormData对象保存表单各字段,而且设置processData: false提交时不对数据做任何处理,contentType: false不设置contentType类型,这是AJAX针对表单数据提交的几个需要注意的地方。通过url属性可推导出AJAX向视图函数add_person提交了数据,并根据返回的值进行处理。如果有报错信息,就显示在相应的文本框下面,如果增加记录成功则通过location.href = data.url_or_msg返回列表页面。

在要输入姓名的input标签的onblur事件中调用了AJAX对姓名进行了校验,通过get请求向后端视图函数test_name

发送员工姓名,视图函数从数据库表中查询是否有重复姓名然后返回相应的信息给AJAX的success指定的函数处理。

posted @ 2021-07-23 21:59  KKKyrie  阅读(117)  评论(0编辑  收藏  举报