利用bootstrap模态框+ajax对数据进行增删改

接上篇:
1.数据库改动,添加外键,多对多
model.pycss

from django.db import models

# Create your models here.
GENDER = {
    ('male', '男'),
    ('female', '女'),
}
class User(models.Model):
    username=models.CharField(max_length=32,null=False)
    password=models.CharField(max_length=32,null=False)
    email = models.EmailField(null=True)
    name = models.CharField(max_length=20, null=True)
    tel = models.CharField(max_length=20, null=True)
    gender = models.CharField(max_length=20, choices=GENDER)
    birthday = models.DateTimeField(null=True)

class Proxy(models.Model):
    ng_name=models.CharField(max_length=20)

class Domain(models.Model):
    domain=models.CharField(max_length=125,null=False)
    src=models.CharField(max_length=125,null=False)
    User=models.ForeignKey(User,on_delete=models.CASCADE)
    m=models.ManyToManyField(Proxy)

核心部分之viewhtml

from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.shortcuts import redirect, render, HttpResponse
from cdnpanel.models import User, Domain, Proxy
import json

def index(request):
    if request.COOKIES.get("is_login"):
        username = request.COOKIES.get('username')
        data = Domain.objects.filter(User__username=username)
        engine = Proxy.objects.all()
        user = User.objects.all()
        return render(request, 'index.html', {'data': data, "engine": engine, "user": user})
    else:
        return redirect('/login')

def login(request):
    if request.method == "POST":
        ajax_rep = {"status": "err", "msg": None}
        user = request.POST.get('username')
        pwd = request.POST.get('password')
        if not User.objects.filter(username=user).exists():
            ajax_rep['msg'] = "用户不存在"
        elif not User.objects.filter(username=user, password=pwd).exists():
            ajax_rep['msg'] = "密码错误"
        else:
            ajax_rep['status'] = 'ok'
            rep = HttpResponse(json.dumps(ajax_rep))
            rep.set_cookie("is_login", True)
            rep.set_cookie("username", user)
            return rep
        return HttpResponse(json.dumps(ajax_rep))
    return render(request, "login.html")

def register(request):
    if request.method == "POST":
        ajax_rsp = {"status": "ok", "msg": None}
        try:
            if request.is_ajax():
                username = request.POST.get('username')
                password = request.POST.get('password')
                name = request.POST.get('name')
                email = request.POST.get('email')
                tel = request.POST.get('tel')
                gender = request.POST.get('gender')
                birthday = request.POST.get('birthday')

                if User.objects.filter(username=username).exists():
                    ajax_rsp["status"] = "err"
                    ajax_rsp["msg"] = "用户已存在"
                else:
                    User.objects.create(
                        username=username,
                        password=password,
                        email=email,
                        name=name,
                        tel=tel,
                        gender=gender,
                        birthday=birthday,
                    )
        except IntegrityError:
            ajax_rsp["status"] = "err"
            ajax_rsp['msg'] = "性别为必选项"
        except ValidationError:
            ajax_rsp["status"] = "err"
            ajax_rsp['msg'] = "日期为必选项"
        return HttpResponse(json.dumps(ajax_rsp))
    else:
        return render(request, "register.html")

def add_domain(request):
    if request.is_ajax():
        print(request.POST)
        ajax_rsp = {'status': "err", "msg": None, "yourself": "yes"}
        try:
            domain = request.POST.get("domain")
            src = request.POST.get("src")
            user = request.POST.get("username")
            if not user == request.COOKIES.get('username'):
                ajax_rsp["yourself"] = "no"
            user_id = User.objects.get(username=user).id
            ng_id = []
            ng = request.POST.getlist('ng_name')
            for n in ng:
                nid = Proxy.objects.get(ng_name=n).id
                ng_id.append(nid)
            Domain.objects.create(domain=domain, src=src, User_id=user_id)
            obj = Domain.objects.get(domain=domain)
            obj.m.set(ng_id)
            ajax_rsp['data_id'] = obj.id
            ajax_rsp['status'] = 'ok'
        except Exception as e:
            print(e)
            ajax_rsp['msg'] = str(e)
        return HttpResponse(json.dumps(ajax_rsp))
    return redirect('/index')

def del_domain(request):
    if request.is_ajax():
        ajax_rsp = {'status': "err", "msg": None}
        try:
            del_data_id=request.POST.get("del_data_id")
            print(del_data_id)
            Domain.objects.get(id=del_data_id).delete()
            ajax_rsp['status'] = "ok"
        except Exception as e:
            print(e)
            ajax_rsp['msg'] = str(e)
        return HttpResponse(json.dumps(ajax_rsp))

def update_domain(request):
    if request.is_ajax():
        if request.method == "GET":
            ajax_rsp = {"status": "err"}
            try:
                data_id=request.GET.get("data_id")
                domain=Domain.objects.filter(id=data_id).first()
                ajax_rsp["domain"]=domain.domain
                ajax_rsp["src"]=domain.src
                ajax_rsp["user"]=User.objects.get(domain__domain=domain.domain,domain__id=data_id).username
                engine_list=[]
                for item in Proxy.objects.filter(domain__domain=domain.domain):
                    engine_list.append(item.ng_name)
                ajax_rsp["engine"]=engine_list
                ajax_rsp["status"]='ok'
                print(ajax_rsp)
            except Exception as e:
                print(e)
                ajax_rsp['msg'] = str(e)
            return HttpResponse(json.dumps(ajax_rsp))
        elif request.method == "POST":
            print(request.POST)
            ajax_rsp = {'status': "err", "msg": None, "yourself": "yes"}
            try:
                old_id = request.POST.get("data_id")
                domain = request.POST.get("domain")
                src = request.POST.get("src")
                user = request.POST.get("username")
                if not user == request.COOKIES.get('username'):
                    ajax_rsp["yourself"] = "no"
                user_id = User.objects.get(username=user).id
                ng_id = []
                ng = request.POST.getlist('ng_name')
                for n in ng:
                    nid = Proxy.objects.get(ng_name=n).id
                    ng_id.append(nid)
                Domain.objects.filter(id=old_id).update(domain=domain, src=src, User_id=user_id)
                obj = Domain.objects.get(domain=domain,src=src)
                obj.m.set(ng_id, clear=True)
                ajax_rsp['status'] = 'ok'
            except Exception as e:
                ajax_rsp['msg'] = str(e)
            return HttpResponse(json.dumps(ajax_rsp))

def test(request):
    print(Domain.objects.get(domain="2343165sada4864sdsa.tw"))
    return render(request, 'test.html')

核心部分之index.html前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
{% load static %}
<link rel="stylesheet" href="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<style>
    .table{
        width: 300px;
    }
</style>
<body>
    <p></p>
    <div>
        <button type="button" class="btn btn-success" data-toggle="modal" data-target="#addModal">添加</button>
    </div>
    <p></p>
    <div>
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>域名</th>
                <th>源</th>
                <th>操做</th>
            </tr>
            </thead>
            <tbody>
                {% for item in data %}
                    <tr data_id="{{ item.id }}">
                    <td>{{ item.domain }}</td>
                    <td>{{ item.src }}</td>
                    <td>
                        <a data-toggle="modal" data-target="#delModal" id="del_icon"   class="fa fa-trash-o fa-lg"></a>
                        <a data-toggle="modal" data-target="#editModal"    class="fa fa-pencil fa-fw"></a>
                    </td>
                    </tr>
                {% endfor %}
            </tbody>
{# 添加模态对话框#}
    <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="addModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
            <h4 class="modal-title" id="addModalLabel">New message</h4>
          </div>
          <div class="modal-body">
            <form action="add_domain" id="modal_form" method="post">
              <div class="form-group">
              <label for="inputEmail3" class="col-sm-2 control-label">域名:</label>
                  <input type="text" name="domain" class="form-control" id="inputEmail3" placeholder="域名">
              </div>
              <div class="form-group">
                  <label  class="col-sm-2 control-label">源:</label>
                  <input  name="src" class="form-control"  placeholder="1.1.1.1">
              </div>
                 <div class="form-group">
                     {% for ng in engine %}
                     <input type="checkbox" name="ng_name" value="{{ ng.ng_name }}">{{ ng.ng_name }}
                     {% endfor %}
                 </div>
                <div class="form-group">
                        <select name="username" >
                              {% for u in user %}
                                  <option value="{{ u.username }}">{{ u.username }}</option>
                              {% endfor %}
                        </select>
                </div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-submit add_submit">提交</button>
          </div>
        </div>
      </div>
    </div>
        </table>
    </div>

{#删除模态框#}
<!-- Modal -->
<div class="modal fade " id="delModal" tabindex="-1" role="dialog" aria-labelledby="delModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content ">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="delModalLabel" style="color: red" >危险!!</h4>
      </div>
      <div class="modal-body alert alert-danger" >
        此操做不能够逆!是否删除?
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-danger del_submit">确认删除</button>
      </div>
    </div>
  </div>
</div>

{#编辑模态框#}
    <div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
            <h4 class="modal-title" id="editModalLabel">update</h4>
          </div>
          <div class="modal-body">
            <form action="update_domain" id="modal_form" method="post">
              <div class="form-group">
              <label for="inputEmail3" class="col-sm-2 control-label">域名:</label>
                  <input type="text" name="domain" class="form-control" id="inputEmail3" >
              </div>
              <div class="form-group">
                  <label  class="col-sm-2 control-label">源:</label>
                  <input  name="src" class="form-control"  >
              </div>
                 <div class="form-group">
                     {% for ng in engine %}
                     <input type="checkbox" name="ng_name" value="{{ ng.ng_name }}">{{ ng.ng_name }}
                     {% endfor %}
                 </div>
                <div class="form-group">
                        <select name="username" >
                              {% for u in user %}
                                  <option value="{{ u.username }}">{{ u.username }}</option>
                              {% endfor %}
                        </select>
                </div>
            </form>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            <button type="button" class="btn btn-submit edit_submit">提交</button>
          </div>
        </div>
      </div>
    </div>
        </table>
    </div>

</body>
<script src="/static/js/jquery-3.5.1.min.js"> </script>
<script src="{% static 'plugin/bootstrap/js/bootstrap.min.js' %}"> </script>
<script>
    $(".add_submit").click(function (){
        var data=$("#addModal form").serialize()
        console.log(data)
        $.ajax({
            data:data,
            dataType:"json",
            "type":"POST",
            "url":'/add_domain',
            "success":function (arg) {
                {#若添加的是本身的数据则在前端显示#}
                if(arg.yourself=="yes") {
                    console.log(arg.msg)
                    postdata = "{\"" + data.replace(RegExp("=", "g"), "\":\"").replace(RegExp("&", 'g'), "\",\"") + "\"}";
                    postdata = JSON.parse(postdata)
                    console.log(postdata.domain)
                    data_id=arg.data_id
                    var tr_ele = $("<tr></tr>")
                    tr_ele.attr("data_id",data_id)
                    var dtd_ele = $("<td></td>").text(postdata.domain)
                    var std_ele = $("<td></td>").text(postdata.src)
                    var action_ele = '<td><a data-toggle="modal" data-target="#delModal" id="del_icon"  class="fa fa-trash-o fa-lg"></a> <a data-toggle="modal" data-target="#editModal" class="fa fa-pencil fa-fw"></a></td>'
                    tr_ele.append(dtd_ele)
                    tr_ele.append(std_ele)
                    tr_ele.append(action_ele)
                    $("tbody").append(tr_ele)
                }
                $('#addModal').modal('hide')
                                document.getElementById("modal_form").reset()
            }
        })
    })
{#   删除函数 #}
    var data_id;
    {# 定义一个全局变量传递修改数据的id值 #}
    {#$(".fa-trash-o").click(function (){#}
    $(document).on("click",".fa-trash-o",function (){
        data_id=$(this).parent().parent().attr("data_id")
        $(this).parent().parent().attr("id","del_targer"){# 由于无法经过data_id删除元素,给点击的tr标签加了个惟一id标识 #}
        $(".del_submit").click(function(){
            var postdata={};
            postdata['del_data_id']=data_id
            console.log(data_id)
            $.ajax({
                data:postdata,
                dataType:"json",
                "type": "POST",
                "url":'/del_domain',
                "success":function (arg){
                    if(arg.status=="ok"){
                        $("#del_targer").remove()
                        $('#delModal').modal('hide')
                    }
                }
            })
        })
    })

{#   编辑函数 #}
{#    $(".fa-pencil").click(function (){#}
    $(document).on("click",".fa-pencil",function (){
        data_id=data_id=$(this).parent().parent().attr("data_id") {# 直接从前端获取数据太麻烦,这里用ajax获取数据赋值#}
        $(this).parent().parent().attr("id","edit_targer")
        $.ajax({
            type:"GET",
            data:{"data_id":data_id},
            "url":'/update_domain',
            dataType:"json",
            "success":function (arg){
                    if(arg.status=="ok"){
                        $("#editModal input[name='domain']").val(arg.domain)
                        $("#editModal input[name='src']").val(arg.src)
                        $("#editModal option[value="+arg.user+"]").prop("selected",true)
                        for (item in arg.engine)
                        {
                            ng_name=arg.engine[item]
                            $("#editModal input[value="+ng_name+"]").prop("checked",true)
                        }

                    }
            }
        })
        $(".edit_submit").click(function (){
            var data=$("#editModal form").serialize()
            postdata = "{\"" + data.replace(RegExp("=", "g"), "\":\"").replace(RegExp("&", 'g'), "\",\"") + "\"}";
            postdata = JSON.parse(postdata)
            postdata["data_id"]=data_id
            $.ajax({
                data:postdata,
                dataType:"json",
                "type":"POST",
                "url":'/update_domain',
                "success":function (arg) {
                    {#若修改的是本身的数据则在前端显示#}
                    if (arg.status == 'ok') {
                        if (arg.yourself == "yes") {
                            var tr_ele = $("#edit_targer")
                            tr_ele.empty()
                            var dtd_ele = $("<td></td>").text(postdata.domain)
                            var std_ele = $("<td></td>").text(postdata.src)
                            var action_ele = '<td><a data-toggle="modal" data-target="#delModal" id="del_icon"  class="fa fa-trash-o fa-lg"></a> <a data-toggle="modal" data-target="#editModal" class="fa fa-pencil fa-fw"></a></td>'
                            tr_ele.append(dtd_ele)
                            tr_ele.append(std_ele)
                            tr_ele.append(action_ele)
                        }else {
                            var tr_ele = $("#edit_targer")
                            tr_ele.empty()
                        }
                        $('#editModal').modal('hide')
                        $("#edit_targer").attr("id","")
                    }
                }
            })

        })
    })
    $(".btn-default").click(function (){
        document.getElementById("modal_form").reset()
        $(":checked").prop("checked",false)
        $(":selected").prop("selected",false)
        $("#del_targer").attr("id","")
        $("#edit_targer").attr("id","")
    })
</script>
</html>

url部分jquery

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path('index', views.index),
    re_path('register', views.register),
    re_path('login', views.login),
    re_path('add_domain', views.add_domain),
    re_path('del_domain', views.del_domain),
    re_path('update_domain', views.update_domain),
    re_path('test', views.test),

]

思路历程简介:ajax

1.登录
上篇的登录没有设置cookie,因此每次都要重复登录,操做其实很简单,当用户名和密码匹配成功了,在cookie中设置自定义字段is_login=true,而后在index函数中取得该值并判断,代码部分以下数据库

def index(request):
    if request.COOKIES.get("is_login"):
        username = request.COOKIES.get('username')
        data = Domain.objects.filter(User__username=username)
        engine = Proxy.objects.all()
        user = User.objects.all()
        return render(request, 'index.html', {'data': data, "engine": engine, "user": user})
    else:
        return redirect('/login')

def login(request):
    if request.method == "POST":
        ajax_rep = {"status": "err", "msg": None}
        user = request.POST.get('username')
        pwd = request.POST.get('password')
        if not User.objects.filter(username=user).exists():
            ajax_rep['msg'] = "用户不存在"
        elif not User.objects.filter(username=user, password=pwd).exists():
            ajax_rep['msg'] = "密码错误"
        else:
            ajax_rep['status'] = 'ok'
            rep = HttpResponse(json.dumps(ajax_rep))
            rep.set_cookie("is_login", True)
            rep.set_cookie("username", user)
            return rep
        return HttpResponse(json.dumps(ajax_rep))
    return render(request, "login.html")

2.添加数据
添加数据流程主要是:获取数据-->处理数据-->取得返回结果后展现django

获取数据前还要先作填写数据的模态框,这里主要有个问题,由于涉及外键和多对多,因此要先有这些数据能够选,也就是模板里面必须传入外键表的值和多对多的值,我这里是
render(request, 'index.html', {'data': data, "engine": engine, "user": user})
而后用select元素做为多对多的选择项,checkbox为User的单选json

<1>获取数据
由于填数据用的是form表单,因此这里获取数据很简单用serialize()函数
var data=$("#addModal form").serialize()
<2>处理数据
利用ajax传送,view函数处理便可
<3>数据显示
这里有个问题,serialize()函数处理出来的数据不是字典形式,而是相似get请求的形式:”username=linzb&password=123456“,因此要对其进行分割取值,才能对元素进行赋值
(这里我还多赋值一个yourself字段,判断是否为当前登陆用户,是才显示)bootstrap

3.删除
要删除,首先服务端要知道数据是什么,其次,服务端删除成功后,前端要删除对应元素,因此删除部分能够归结为一个问题:如何对原来的数据进行定位?cookie

这里我利用了一个全局变量data_id(生成数据的时候在tr上赋值数据id),在点击删除按钮的时候,经过this关键字找到这个数据id并传递给data_id,并在id打了个del_tager标记,因而问题解决:
<1>data_id经过ajax传递给服务端,服务端找到对应数据del
<2>返回结果后,前端经过#del_tager找到标签并删除
(这里也许有人会问为何不直接经过data_id,而要画蛇添足,这是由于我测试屡次这方法行不通,才选择用del_targer)

4.编辑
编辑比添加多了两步
<1>打开模态框的时候要为模态框赋值(这里我采用ajax从服务端取值,这方法不推荐,从前端取值对服务端更友善)
<2>成功执行后要在前端进行修改而不是添加

debug:

1.django 设置cookie须要用变量过渡,直接引用会报错
    正确:
        rep=HttpResponse(json.dumps(ajax_rep))
        rep.set_cookie("is_login",True)
        return rep
    错误:
        return HttpResponse(json.dumps(ajax_rep)).set_cookie("is_login",True)

2. 给标签加 data-toggle="modal" data-target="#exampleModal"属性,点击没反应

    测试发现是忘了加载bootstrap.min.js

3.ValueError: too many values to unpack (expected 2)

排查发现:Proxy.objects.get(ng_name=n).id写成了:
    Proxy.objects.get(n).id  少了字段名

4.添加时的元素位置和插入问题

想要的代码形式:
<tbody>
    <tr>
        <td>已存在的数据</tr>
    </tr>
    <tr>
        <td>新增长的数据<td>
    </tr>
</tbody>

    var tr_ele =$("<tr></tr>")
    var dtd_ele =$("<td></td>").text(新增长的数据)
    tr_ele.append(std_ele)
    $("tbody").append(tr_ele)

以前用:tr_ele.text(dtd_ele)和$("tbody tr").append(tr_ele)一直搞不定
错误缘由在于没有意识到append是在内部添加,before()和after() 是在外部

5.Bootstrap 模态框使用
<1>以id为标识,内容标签包裹头部,body和尾部
<div class="modal fade" id="delModal" tabindex="-1" role="dialog" aria-labelledby="delModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
      </div>
      <div class="modal-body " >
      </div>
      <div class="modal-footer">
      </div>
    </div>
  </div>
</div>

<2>用data-target指向id引用
    <a data-toggle="modal" data-target="#delModal" id="del_icon"  class="fa fa-trash-o fa-lg"></a>

6.jquery  attr()和prop()区别
<1>取自定义属性用attr()
(下面摘抄自:https://www.jb51.net/article/140974.htm)
1.添加属性名称该属性就会生效应该使用prop();
2.是有true,false两个属性使用prop();(如'checked','selected','disabled'等)
3.其余则使用attr();

7.模态框退出,清空表单输入值的方法(利用form表单的reset)
    因为jquery没有reset()方法,能够给表单赋予id,而后reset()
    document.getElementById("modal_form").reset()
    选择按钮则须要去掉对应属性
    $(":checked").prop("checked",false)
    $(":selected").prop("selected",false)

8.编辑模态框完成后发现添加数据时报错

    后面print (POST数据)发现数据取了多行
    缘由:取数据时没有区分form表单
    原来:var data=$("form").serialize()
    修改:var data=$("#addModal form").serialize()

9.多对多表更新,加上clear=True就能够
    obj.m.set(ng_id,clear=True)
    意为先清空后添加

10.作删除的时候利用tr传递data_id,添加的时候也必须加上
11.事件委托on语法:
    $(document).on("click",".fa-trash-o",function (){})
    on("事件","选择标签",函数(){})

删除时的思路:点击模态按钮时必须获取当前的值,用全局变量传递
要删除整行,因而放在tr标签上
12.若是发现清空数据有问题用(找到对应位置便可,51编辑器很差用,懒得重复改):
           document.getElementById("modal_form").reset()
        $(":checked").prop("checked",false)
        $(":selected").prop("selected",false)
        $("#del_targer").attr("id","")
        $("#edit_targer").attr("id","")