接上篇:
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","")