CURD
CURD是一个数据库技术中的缩写词,一般的项目开发的各种参数的基本功能都是CURD。作用是用于处理数据的基本原子操作。
它代表创建(Create)、更新(Update)、读取(Retrieve)和删除(Delete)操作。
核心
1.前端页面通过ajax方式请求后台数据库数据
2.后台 配置文件 指定字段去数据库取相应的字段返回给前端ajax
3.前端通过jquery 实现前端页面数据修改,将修改数据再次通过ajax返回给后台
具体实现
前端ajax获取数据
在js自执行函数中,写入代码,定义全局变量 requestURL,方便后面传入新的ajax 提交路径,以ajax以get方式去后台获取数据. 获取到后台 result 数据,将其传递到 对应函数执行
requestURL = null; function init(pager) { $.ajax( { url:requestURL, data:{'pager':pager}, type:'GET', dataType:'JSON', success:function (result) { initchoice(result.choice_dict); initheader(result.table_config); initbody(result.table_config,result.info) } } ) };
定义配置文件(整合 前端/数据库数据/显示样式)
在后台 视图页面定义一个配置文件:
数据结构为: 列表[字典方式]
id , 作为数据库中的字段.
title,前端显示的字段名
display,是否在前端显示
text,在前端可定义显示内容
attrs,样式定义,提交name定义,修旧数值定义,文本类型定义(input?select?其他)
table_config = [ { 'id': None, 'title': '选项', 'display': 1, 'text': {'key': "<input type='checkbox' />", 'val': {}}, 'attrs': {}, }, { 'id':'id', 'title':'ID', 'display':1, 'text':{'key':"{n}",'val':{'n':'@id'}}, 'attrs':{}, }, { 'id': 'title', 'title': '标题', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@title'}}, 'attrs': {'name':'title',"origin":'@title','edit-enable':'true','edit-type':'input'}, }, { 'id': 'status', 'title': '状态', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@@device_type_choice'}}, 'attrs': {'name':'status',"origin":'@status','edit-enable':'true','edit-type':'select',"global-name":'device_type_choice'}, }, { 'id': 'pro_id', 'title': '处理人', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@@device_type_userinfo'}}, 'attrs': {'name':'pro_id',"origin":'@pro_id','edit-enable':'true','edit-type':'select',"global-name":'device_type_userinfo'}, }, { 'id': 'sol', 'title': '处理详情', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@sol'}}, 'attrs': {'name': 'sol', "origin": '@sol', 'edit-enable': 'true', 'edit-type': 'input'}, }, { 'id': None, 'title': '操作', 'display': 1, 'text': {'key': "<a href='#'>添加</a>|<a href='#'>删除</a>", 'val': {}}, 'attrs': {}, }, ]
数据库表(贴出来做参考的,上面只是截取了表中部分字段显示)
class Fault(models.Model): id = models.AutoField(primary_key=True,null=False) title = models.CharField(max_length=20,verbose_name="报障标题") detail = models.TextField(verbose_name="报障详细信息") user_id = models.ForeignKey('Userinfo', to_field='uid', on_delete=models.CASCADE, verbose_name="报障人", related_name='u') choice = ( (1, '待处理'), (2, '处理中'), (3, '已处理'), ) status = models.IntegerField(choices=choice,verbose_name='处理状态',default=1) ctime = models.DateTimeField(null=False, auto_now_add=True, verbose_name='创建时间') pro = models.ForeignKey('Userinfo', to_field='uid', on_delete=models.CASCADE, verbose_name="处理人", null=True, blank=True, related_name='p', ) sol = models.TextField(null=True,verbose_name="解决方案") ptime = models.DateTimeField(null=True)
获取冲数据库中获取指定字段数据
视图将配置文件中id字段循环出来加入到zd列表列表中,然后去数据库中取指定字段的数据,将其整合到result字典中,转为json字符串传递到 前端ajax 回到函数中.
def ajaxdate(request): import json if request.method == "GET": table_config = [...] zd = [] for i in table_config: if i['id']: zd.append(i['id']) info = models.Fault.objects.values(*zd).all() choice = models.Fault.choice userinfo = models.Userinfo.objects.all().values_list('uid','uname') result = { 'table_config':table_config, 'info':list(info), 'choice_dict':{'device_type_choice':choice,'device_type_userinfo':list(userinfo)}, } return HttpResponse(json.dumps(result))
ajax回到执行函数(显示表头、显示主体数据、添加html全局变量)
这样就将后台的表头,数据都显示到前端
// {#列表表头显示部分#} function initheader(table_config) { var tr = document.createElement('tr'); $.each(table_config,function (k,item) { var th = document.createElement('th'); if (item.display){ th.innerHTML = item.title; $(tr).append(th); } }); $('#table_th').empty(); $('#table_th').append(tr); } // {#列表数据显示部分#} function initbody(table_config,info){ $('#table_td').empty(); $.each(info,function (i,j) { var tr = document.createElement('tr'); tr.setAttribute('j-id',j['id']); var dictinfo = {}; $.each(table_config,function (x,y) { if (y.display) { $.each(y.text.val,function (k,v) { if(v.substring(0,2) ==='@@'){ var gname = v.substring(2,v.length); var gid = j[y.id]; var t = test(gname,gid); dictinfo[k] =t; }else if (v[0] ==='@'){ dictinfo[k] = j[v.substring(1,v.length)]; }else { dictinfo[k] = v;} }); var td = document.createElement('td'); var ss = y.text.key.format(dictinfo); td.innerHTML = ss; $.each(y.attrs,function (q,t) { if(t[0] === '@'){ td.setAttribute(q,j[t.substring(1,t.length)]); }else { td.setAttribute(q,t) } }); $(tr).append(td);} }); $('#table_td').append(tr)})} // {#choice数据类型,定义全局变量#} function initchoice(choice_dict) { $.each(choice_dict,function (i,j) { window[i]=j; }) } // {#将以数据id去choice全局变量取对应的 中文显示信息#} function test(gname,gid) { var ret = null; $.each(window[gname], function (k, item) { if (item[0] === gid) { ret = item[1]; return } }); return ret; }
前端html 添加操作按钮
<h1>用户信息</h1> <div class="btn-group" role="group" aria-label="..."> <button id="bindall" type="button" class="btn btn-default">全选</button> <button id="bindfx" type="button" class="btn btn-default">反选</button> <button id="unbindall" type="button" class="btn btn-default">取消</button> <button id="bindbj" type="button" class="btn btn-default">进入编辑模式</button> <button type="button" class="btn btn-default">批量删除</button> <button id='save' type="button" class="btn btn-default">保存</button> </div> <table class="table table-bordered table-hover"> <thead id="table_th"></thead> <tbody id="table_td"></tbody> </table>
自定义format字符串方法
// {#自定义的 字符format的方法#} String.prototype.format = function(kwargs){ var ret = this.replace(/{(w+)}/g,function (k,m) { return kwargs[m] }); return ret };
用jquery绑定事件
function bindsave(){ $('#save').click(function () { var postlist=[]; $('#table_td').find('tr[has-edit="true"]').each(function () { var temp = {}; var id = $(this).attr('j-id'); temp['id'] = id; $(this).children('[edit-enable="true"]').each(function () { var name = $(this).attr('name'); var origin = $(this).attr('origin'); var newval = $(this).attr('new-val'); if(origin != newval){ temp[name] = newval; }; }) postlist.push(temp); $.ajax({ url:requestURL, type:'POST', data:{'post_list':JSON.stringify(postlist)}, dataType:'Json', success:function (arg) { if(arg.status){ init(1); }else { alter(arg); } } }) }) }) } function bindM() { $('#bindbj').click(function () { var ed = $(this).hasClass('btn-warning'); if(ed){ $(this).removeClass('btn-warning'); $(this).text("进入编辑模式"); $('#table_td').find(':checked').each(function () { var $cur = $(this).parent().parent(); bjhangout($cur); }) }else { $(this).addClass('btn-warning'); $(this).text("退出编辑模式"); $('#table_td').find(':checked').each(function () { var $cur = $(this).parent().parent(); bjhang($cur); }) } }) } function bindC() { // {#$('#table_td').find(':checkbox').click() // 这种方式新增数据无法被选中#} $('#table_td').on('click',':checkbox',function () { if($('#bindbj').hasClass('btn-warning')){ var ck = $(this).prop('checked'); var $cur = $(this).parent().parent(); if(ck){ // {#console.log("进入编辑模式");#} bjhang($cur) }else{ // {#console.log("退出编辑模式");#} bjhangout($cur) } } }) } function bjhang(cur) { cur.attr('has-edit','true'); cur.children().each(function () { cur.addClass('success'); var editenable = $(this).attr('edit-enable'); var editetype = $(this).attr('edit-type'); if (editenable === 'true'){ if(editetype === 'select'){ var globalname = $(this).attr("global-name"); var origin = $(this).attr("origin"); var sel = document.createElement('select'); sel.className = "form-control"; $.each(window[globalname],function (k,v) { var op = document.createElement('option'); op.innerHTML = v[1]; op.setAttribute('value',v[0]); $(sel).append(op) }); $(sel).val(origin); $(this).html(sel); }else if(editetype === 'input'){ var intext = $(this).text(); var tag = document.createElement('input'); tag.className = "form-control"; tag.value = intext; $(this).html(tag) } }})} function bjhangout(cur) { cur.removeClass('success'); cur.children().each(function () { var editenable = $(this).attr('edit-enable'); if (editenable === 'true'){ var editetype = $(this).attr('edit-type'); if(editetype === 'select'){ var $select = $(this).children().first() ; var newid = $select.val(); var newtext = $select[0].selectedOptions[0].innerHTML; $(this).html(newtext); $(this).attr('new-val',newid) }else if(editetype === 'input'){ var $input2 = $(this).children().first() ; var tag2 = $input2.val(); $(this).html(tag2); $(this).attr('new-val',tag2) }}})} function bindall() { $('#bindall').click(function () { $('#table_td').find(':checkbox').each(function () { if($('#bindbj').hasClass('btn-warning')){ if($(this).prop('checked')){ }else { $(this).prop('checked',true); var $cur = $(this).parent().parent(); bjhang($cur) } }else { $(this).prop('checked',true); }; }) }) } function unbindall() { $('#unbindall').click(function () { $('#table_td').find(':checked').each(function () { if($('#bindbj').hasClass('btn-warning')){ $(this).prop('checked',false); var $cur = $(this).parent().parent(); bjhangout($cur); }else { $(this).prop('checked',false); } }) }) } function bindfx() { $('#bindfx').click(function () { $('#table_td').find(':checkbox').each(function () { if($('#bindbj').hasClass('btn-warning')){ var $cur = $(this).parent().parent(); if ($(this).prop('checked')){ $(this).prop('checked',false); bjhangout($cur); }else { $(this).prop('checked',true); bjhang($cur); } }else { if ($(this).prop('checked')){ $(this).prop('checked',false); }else { $(this).prop('checked',true); } } }) }) }
完整代码
html - 模板
<!DOCTYPE html> <html > <head> <meta charset="UTF-8"> {# <title>Title</title>#} <!--单独子版的title--> <title>{% block title %}{% endblock %}</title> <!--单独子版的css--> {% block css %}{% endblock %} <style> .item{ } .title{ font-size: 20px; } .content{ margin-left: 30px; } .content a{ display: block; } </style> <link type="text/css" rel="stylesheet" href="/static/css/muban-css.css"> <link rel="stylesheet" href="/static/font-awesome-4.7.0/font-awesome-4.7.0/css/font-awesome.min.css"> </head> <body> {#头部 start#} <div class="pg-header"> <!--共享的--> {#头部菜单导航条#} <div class="logo left">Anec后台管理</div> <div class="hl-menu left"> <a href="#" class="item">菜单一</a> <div class="item-set"> <a href="#" class="item">菜单二</a> <div class="sets hide"> <a href="#" >菜单二1</a> <a href="#" >菜单二2</a> <a href="#" >菜单二3</a> </div> </div> <div class="item-set"> <a href="#" class="item">菜单三</a> <div class="sets hide"> <a href="#" >菜单三1</a> <a href="#" >菜单三2</a> <a href="#" >菜单三3</a> </div> </div> <div class="item-set"> <a href="#" class="item">菜单四</a> <div class="sets hide"> <a href="#" >菜单四1</a> <a href="#" >菜单四2</a> <a href="#" >菜单四3</a> </div> </div> </div> {#个人消息通知栏#} <div class="hr-menu right"> <a href="#" class="item"><i class="fa fa-envelope" aria-hidden="true"></i>消息</a> <a href="#" class="item"><i class="fa fa-phone-square" aria-hidden="true"></i>通知</a> <a href="#" class="item"><i class="fa fa-server" aria-hidden="true"></i>任务</a> <div class="avatar"> <a href="#" class="item"> {# <img src="111.jpg" >#} <i class="fa fa-user-circle-o fa-2x" aria-hidden="true"></i> </a> <div class="sets hide"> <a href="#" >菜单1</a> <a href="#" >菜单2</a> <a href="#" >菜单3</a> </div> </div> </div> </div> {#头部 end#} {#div_body start #} <div class="pg-body"> {#body-菜单栏 start#} <div class="menus"> <!--共享的--> <div class="item"> <div class="item-title"><a>功能1</a></div> <div class="item-content "> <a href="/clbzd-ck">报障单</a> <a>功能1-2</a> <a>功能1-3</a> </div> </div> {% block menu %}{% endblock %} </div> {#body-菜单栏 end#} {#body-内容栏 start#} <div class="countents"> <!--单独显示的--> <div class="countents-top"> </div> <div class="countent"> {% block countent %}{% endblock %} </div> </div> {#body-内容栏 end#} </div> {#div_body end #} {#div foot start#} <div class="pg-foot"> <!--共享的--> </div> {#div foot end#} <!--单独子版js--> {% block js %}{% endblock %} </body> </html>
html 代码
{% extends "htmb.html" %} {% block css %} <link rel="stylesheet" href="/static/bootstrap/bootstrap-3.3.7-dist/css/bootstrap.min.css"> {% endblock %} {% block js %} <script src="/static/js/jquery-1.7.1.min.js"></script> <script src="/static/js/cmdbzj.js"></script> <script> $(function () { $.NB( '/ajax-date.html') }) </script> {% endblock %} {% block title %} {% endblock %} {% block menu %} {% endblock %} {% block countent %} <h1>用户信息</h1> <div class="btn-group" role="group" aria-label="..."> <button id="bindall" type="button" class="btn btn-default">全选</button> <button id="bindfx" type="button" class="btn btn-default">反选</button> <button id="unbindall" type="button" class="btn btn-default">取消</button> <button id="bindbj" type="button" class="btn btn-default">进入编辑模式</button> <button type="button" class="btn btn-default">批量删除</button> <button id='save' type="button" class="btn btn-default">保存</button> </div> <table class="table table-bordered table-hover"> <thead id="table_th"></thead> <tbody id="table_td"></tbody> </table> {% endblock %}
封装的JS代码
// 自执行函数 (function () { requestURL = null; // {#自定义的 字符format的方法#} String.prototype.format = function(kwargs){ var ret = this.replace(/{(w+)}/g,function (k,m) { return kwargs[m] }); return ret }; function bindsave(){ $('#save').click(function () { var postlist=[]; $('#table_td').find('tr[has-edit="true"]').each(function () { var temp = {}; var id = $(this).attr('j-id'); temp['id'] = id; $(this).children('[edit-enable="true"]').each(function () { var name = $(this).attr('name'); var origin = $(this).attr('origin'); var newval = $(this).attr('new-val'); if(origin != newval){ temp[name] = newval; }; }) postlist.push(temp); $.ajax({ url:requestURL, type:'POST', data:{'post_list':JSON.stringify(postlist)}, dataType:'Json', success:function (arg) { if(arg.status){ init(1); }else { alter(arg); } } }) }) }) } function bindM() { $('#bindbj').click(function () { var ed = $(this).hasClass('btn-warning'); if(ed){ $(this).removeClass('btn-warning'); $(this).text("进入编辑模式"); $('#table_td').find(':checked').each(function () { var $cur = $(this).parent().parent(); bjhangout($cur); }) }else { $(this).addClass('btn-warning'); $(this).text("退出编辑模式"); $('#table_td').find(':checked').each(function () { var $cur = $(this).parent().parent(); bjhang($cur); }) } }) } function bindC() { // {#$('#table_td').find(':checkbox').click() // 这种方式新增数据无法被选中#} $('#table_td').on('click',':checkbox',function () { if($('#bindbj').hasClass('btn-warning')){ var ck = $(this).prop('checked'); var $cur = $(this).parent().parent(); if(ck){ // {#console.log("进入编辑模式");#} bjhang($cur) }else{ // {#console.log("退出编辑模式");#} bjhangout($cur) } } }) } function bjhang(cur) { cur.attr('has-edit','true'); cur.children().each(function () { cur.addClass('success'); var editenable = $(this).attr('edit-enable'); var editetype = $(this).attr('edit-type'); if (editenable === 'true'){ if(editetype === 'select'){ var globalname = $(this).attr("global-name"); var origin = $(this).attr("origin"); var sel = document.createElement('select'); sel.className = "form-control"; $.each(window[globalname],function (k,v) { var op = document.createElement('option'); op.innerHTML = v[1]; op.setAttribute('value',v[0]); $(sel).append(op) }); $(sel).val(origin); $(this).html(sel); }else if(editetype === 'input'){ var intext = $(this).text(); var tag = document.createElement('input'); tag.className = "form-control"; tag.value = intext; $(this).html(tag) } }})} function bjhangout(cur) { cur.removeClass('success'); cur.children().each(function () { var editenable = $(this).attr('edit-enable'); if (editenable === 'true'){ var editetype = $(this).attr('edit-type'); if(editetype === 'select'){ var $select = $(this).children().first() ; var newid = $select.val(); var newtext = $select[0].selectedOptions[0].innerHTML; $(this).html(newtext); $(this).attr('new-val',newid) }else if(editetype === 'input'){ var $input2 = $(this).children().first() ; var tag2 = $input2.val(); $(this).html(tag2); $(this).attr('new-val',tag2) }}})} function bindall() { $('#bindall').click(function () { $('#table_td').find(':checkbox').each(function () { if($('#bindbj').hasClass('btn-warning')){ if($(this).prop('checked')){ }else { $(this).prop('checked',true); var $cur = $(this).parent().parent(); bjhang($cur) } }else { $(this).prop('checked',true); }; }) }) } function unbindall() { $('#unbindall').click(function () { $('#table_td').find(':checked').each(function () { if($('#bindbj').hasClass('btn-warning')){ $(this).prop('checked',false); var $cur = $(this).parent().parent(); bjhangout($cur); }else { $(this).prop('checked',false); } }) }) } function bindfx() { $('#bindfx').click(function () { $('#table_td').find(':checkbox').each(function () { if($('#bindbj').hasClass('btn-warning')){ var $cur = $(this).parent().parent(); if ($(this).prop('checked')){ $(this).prop('checked',false); bjhangout($cur); }else { $(this).prop('checked',true); bjhang($cur); } }else { if ($(this).prop('checked')){ $(this).prop('checked',false); }else { $(this).prop('checked',true); } } }) }) } // {#用ajax get方式获取后台的json数据#} function init(pager) { $.ajax( { url:requestURL, data:{'pager':pager}, type:'GET', dataType:'JSON', success:function (result) { initchoice(result.choice_dict); initheader(result.table_config); initbody(result.table_config,result.info) } } ) }; // {#列表表头显示部分#} function initheader(table_config) { var tr = document.createElement('tr'); $.each(table_config,function (k,item) { var th = document.createElement('th'); if (item.display){ th.innerHTML = item.title; $(tr).append(th); } }); $('#table_th').empty(); $('#table_th').append(tr); } // {#列表数据显示部分#} function initbody(table_config,info){ $('#table_td').empty(); $.each(info,function (i,j) { var tr = document.createElement('tr'); tr.setAttribute('j-id',j['id']); var dictinfo = {}; $.each(table_config,function (x,y) { if (y.display) { $.each(y.text.val,function (k,v) { if(v.substring(0,2) ==='@@'){ var gname = v.substring(2,v.length); var gid = j[y.id]; var t = test(gname,gid); dictinfo[k] =t; }else if (v[0] ==='@'){ dictinfo[k] = j[v.substring(1,v.length)]; }else { dictinfo[k] = v;} }); var td = document.createElement('td'); var ss = y.text.key.format(dictinfo); td.innerHTML = ss; $.each(y.attrs,function (q,t) { if(t[0] === '@'){ td.setAttribute(q,j[t.substring(1,t.length)]); }else { td.setAttribute(q,t) } }); $(tr).append(td);} }); $('#table_td').append(tr)})} // {#choice数据类型,定义全局变量#} function initchoice(choice_dict) { $.each(choice_dict,function (i,j) { window[i]=j; }) } // {#将以数据id去choice全局变量取对应的 中文显示信息#} function test(gname,gid) { var ret = null; $.each(window[gname], function (k, item) { if (item[0] === gid) { ret = item[1]; return } }); return ret; } jQuery.extend({ 'NB':function (url) { requestURL = url; init(); bindM(); bindC(); bindall(); unbindall(); bindfx(); bindsave(); }, 'changepager':function (num) { init(num); } }) })();
views完整代码
def ajaxdate(request): import json if request.method == "GET": table_config = [ { 'id': None, 'title': '选项', 'display': 1, 'text': {'key': "<input type='checkbox' />", 'val': {}}, 'attrs': {}, }, { 'id':'id', 'title':'ID', 'display':1, 'text':{'key':"{n}",'val':{'n':'@id'}}, 'attrs':{}, }, { 'id': 'title', 'title': '标题', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@title'}}, 'attrs': {'name':'title',"origin":'@title','edit-enable':'true','edit-type':'input'}, }, { 'id': 'status', 'title': '状态', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@@device_type_choice'}}, 'attrs': {'name':'status',"origin":'@status','edit-enable':'true','edit-type':'select',"global-name":'device_type_choice'}, }, { 'id': 'pro_id', 'title': '处理人', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@@device_type_userinfo'}}, 'attrs': {'name':'pro_id',"origin":'@pro_id','edit-enable':'true','edit-type':'select',"global-name":'device_type_userinfo'}, }, { 'id': 'sol', 'title': '处理详情', 'display': 1, 'text': {'key': "{n}", 'val': {'n': '@sol'}}, 'attrs': {'name': 'sol', "origin": '@sol', 'edit-enable': 'true', 'edit-type': 'input'}, }, { 'id': None, 'title': '操作', 'display': 1, 'text': {'key': "<a href='#'>添加</a>|<a href='#'>删除</a>", 'val': {}}, 'attrs': {}, }, ] zd = [] for i in table_config: if i['id']: zd.append(i['id']) info = models.Fault.objects.values(*zd).all() choice = models.Fault.choice userinfo = models.Userinfo.objects.all().values_list('uid','uname') result = { 'table_config':table_config, 'info':list(info), 'choice_dict':{'device_type_choice':choice,'device_type_userinfo':list(userinfo)}, } return HttpResponse(json.dumps(result)) elif request.method == "POST": content = json.loads(request.POST['post_list']) if content: for i in content: models.Fault.objects.filter(id=i['id']).update_or_create(i) ret = {'status':'OK'} return HttpResponse('OK')
此章内容很重要,需练到自己可以脱稿写出来为止!!!!!