Django web 开发(四) - Django项目实践(八)-Ajax的使用与案例

Ajax

浏览器向网站发送请求时,URL 和 表单的形式提交

  • GET
  • POST

特点: 页面刷新

Ajax可以实现向后台偷偷发送请求

  • 依赖JQuery
  • 编写Ajax代码
$.ajax({
    
    
	url:"发送的地址",
	type: "get",
	data:{
    
    
		n1:123,
		n2:456
	},
	success:function(res){
    
    
		console.log(res);
	}
})

GET请求

新建myproject/employee_management/views/task.py

from django.shortcuts import render,HttpResponse


def task_list(request):

    return render(request, "task_list.html")


def task_ajax(request):
    print(request.GET)
    return HttpResponse("成功了")

修改myproject/myproject/urls.py

# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),

新建myproject/employee_management/templates/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 %}

修改myproject/employee_management/templates/layout.html

<li><a href="/task/list/">任务管理</a></li>

...

{% block script %}
{% endblock %}

在这里插入图片描述
在这里插入图片描述
浏览器访问测试,打开F12进入调试界面
在这里插入图片描述
在这里插入图片描述
查看后台输出
在这里插入图片描述

POST请求

修改myproject/employee_management/views/task.py

csrf_exempt可以免除在HTM中写CSRF

from django.shortcuts import render,HttpResponse
from django.views.decorators.csrf import csrf_exempt

def task_list(request):

    return render(request, "task_list.html")

@csrf_exempt
def task_ajax(request):
    print("get请求: ", request.GET)
    print("post请求: ", request.POST)
    return HttpResponse("成功了")

在这里插入图片描述
修改myproject/employee_management/templates/task_list.html
在这里插入图片描述
浏览器访问测试,F12依然开启调试模式
在这里插入图片描述
在这里插入图片描述
查看后台输出
在这里插入图片描述

对上面的Ajax代码进行优化: 绑定事件

修改myproject/employee_management/templates/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">
</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 %}

在这里插入图片描述

返回值

以JSON的方式返回数据

修改myproject/employee_management/templates/task_list.html

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

在这里插入图片描述
浏览器刷新访问
在这里插入图片描述

实现后台接收输入框中的内容

修改myproject/employee_management/templates/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 %}

在这里插入图片描述
在这里插入图片描述

浏览器测试
在这里插入图片描述
查看后台
在这里插入图片描述

假如前端代码过多,我们需要用更简单的方法批量处理

修改myproject/employee_management/templates/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>示例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();
    })


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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
浏览器进行测试
在这里插入图片描述
查看后台
在这里插入图片描述

这样,我们就学会了如何在浏览器页面不刷新的情况下,如何向后台提交数据

接下来正式开始Ajax的案例

任务添加(一)

首先为该页面创建一个表

编辑myproject/employee_management/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)

更新信息

python3 manage.py makemigrations
python3 manage.py migrate

编辑myproject/employee_management/views/task.py

from employee_management.utils.modelform import BootStrapModelForm
from employee_management.models import Task


class TaskModelForm(BootStrapModelForm):
    class Meta:
        model = Task
        fields = "__all__"


@csrf_exempt
def task_list(request):
    form = TaskModelForm()
    return render(request, "task_list.html", {
    
    "form": form})

编辑myproject/employee_management/templates/task_list.html

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

在这里插入图片描述
浏览器访问
在这里插入图片描述
但是会有一个问题存在
在这里插入图片描述
解决办法:编辑myproject/employee_management/models.py

def __str__(self):
return self.username

class Admin(models.Model):
    """管理员"""
    username = models.CharField(verbose_name="用户名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)

    def __str__(self):
        return self.username

在这里插入图片描述

接下来实现将添加的数据发送到后台

优化一下前端的展示样式
编辑myproject/employee_management/templates/task_list.html

注意: 下面前端代码中的button标签必须放在form表单的外面,不然submit的 Ajax 触发机制不会生效

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

在这里插入图片描述

在这里插入图片描述

任务添加(二)

编辑myproject/employee_management/views/task.py

from django import forms

class TaskModelForm(BootStrapModelForm):
    class Meta:
        model = Task
        fields = "__all__"
        widgets = {
    
    
            "detail": forms.TextInput,
        }

...

@csrf_exempt
def task_add(request):
    print(request.POST)
    data_dict = {
    
    "status": True}
    return HttpResponse(json.dumps(data_dict))

编辑myproject/myproject/urls.py

path('task/add/', task.task_add),

浏览器访问测试
在这里插入图片描述
后台查看输出内容
在这里插入图片描述

接下来保存数据并进行数据校验

编辑myproject/employee_management/views/task.py

@csrf_exempt
def task_add(request):
    print(request.POST)

    # 1.用户发送过来的数据进行校验(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))

编辑myproject/employee_management/templates/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 %}

在这里插入图片描述
在这里插入图片描述

在上面的 HTML 代码中,我在操作时很奇怪为什么错误信息会显示在输入框的下面,然后又看了一遍武佩奇老师的视频,发现原理是这样的

ModelForm 在生成页面标签时,会在 input 标签上自动加入required id,它的值由id_ + input标签的name属性的值组成
在这里插入图片描述
而在 HTML 中 Javascript 的一行代码,自动在下一行的标签中加入了数据

$("#id_" + name).next().text(data[0]);

明白了吧?
ok

任务列表

在上面 HTML 代码的基础上进行添加,包括:

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

编辑myproject/employee_management/templates/task_list.html

location.reload();

在这里插入图片描述

  • 实现分页与搜索
    编辑myproject/employee_management/templates/task_list.html,在<div class="container">内加入如下代码
<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>

编辑myproject/employee_management/views/task.py

from employee_management.utils.pagination import Pagination


@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_string

    ##########################################################
    context = {
    
    
        "queryset": page_queryset,
        "form": form,
        "page_string": page_string,
        "search_data": search_data,
    }

    return render(request, "task_list.html", context)

在这里插入图片描述
到这里,任务列表先放一放,进行下一节的操作

猜你喜欢

转载自blog.csdn.net/qq_43139145/article/details/128716339