Python 实战一
列表ID的显示
起初ID显示的是数据库中的id,因为数据库中的id是自增长的,所以删除一条后,这里显示就叉开了,这里使用索引的方式来显示。
这个功能实现的逻辑:
第一:定义一个表格的架构,用id=‘idc-list’来获取表格tbody的内容
1 <table id='my-idc-table' class='table table-bordered'> 2 <thead> 3 <tr> 4 <th>ID</th> 5 <th>机房</th> 6 <th>手机</th> 7 <th>操作</th> 8 </tr> 9 </thead> 10 <tbody id="idc-list"></tbody> 11 12 </table>
第二步:使用jquery来获取tbody的数据。利用each循环来排列后端返回给的数据
1 function getList(){ 2 $.getJSON('/listapi?table_name=idc',function(res){ 3 var html_str = '' 4 $.each(res,function(i,j){ 5 html_str += '<tr>' 6 html_str += '<td>'+j[3]+'</td>' 7 html_str += '<td>'+j[1]+'</td>' 8 html_str += '<td>'+j[2]+'</td>' 9 html_str += '<td><button class="del-btn btn btn-danger btn-xs" data-name="'+j[1]+'" data-id="'+j[0]+'">delete</button></td>' 10 html_str += '</tr>' 11 }) 12 //console.log([$('#idc-list').html()]) 13 14 render_table('my-idc-table',html_str) 15 16 }) 17 } 18 19 getList()
这里使用到了定义到laylou2.html中的render_table函数
1 function render_table(table_id,html_str){ 2 var $table = $('#'+table_id) 3 4 var $tbody = $table.find('tbody') 5 6 if($tbody.html()){ 7 $table.DataTable().destroy() #销毁实例,这个DataTable是用的第三方插件,来显示table的 8 } 9 $tbody.html(html_str) 10 $table.DataTable({ 11 12 bLengthChange:false #开关,是否显示一个每页长度的选择条(须要分页器支撑) 13 }); 14 }
第三步:在后端把数据传递给前端之前,就可以吧索引加上。
后端通过在数据库中select * form 表名; 获取到的数据是个元组,格式如下:
((12L, u'\u5929\u6d25', u'1810'), (13L, u'\u6cb3\u5317', u'188'), (14L, u'\u5317\u4eac', u'1999'), (15L, u'\u5317\u4eac', u'199'), (16L, u'\u53f0\u6e7e', u'111'), (20L, u'\u6d77\u5357', u'1234'))
然后在后端把索引加入。
1 def listapi(): 2 rev_table_name = request.args.get('table_name') 3 result = db.list(rev_table_name) 4 new_result = [] 5 for i in range(len(result)): 6 new_result.append(list(result[i]) + [i+1]) #利用数组相加的方法给添加上索引 7 print new_result 8 return json.dumps(new_result)
方法二:利用列表生成式来简写 [list(a[i])+[i+1] for i in range(len(a))] ,原理一样
方法三:如何用map实现?
增加用户的实现
前端代码:
1 <button id='add-idc' data-toggle="modal" data-target="#add-idc-modal" class='btn btn-primary'>新增机房</button> 2 3 <table id='my-idc-table' class='table table-bordered'> 4 <thead> 5 <tr> 6 <th>ID</th> 7 <th>机房</th> 8 <th>手机</th> 9 <th>操作</th> 10 </tr> 11 </thead> 12 <tbody id="idc-list"></tbody> 13 14 </table> 15 <!-- Modal --> 16 <div class="modal fade" id="add-idc-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 17 <div class="modal-dialog modal-sm" role="document"> 18 <div class="modal-content"> 19 <div class="modal-header"> 20 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> 21 <h4 class="modal-title" id="myModalLabel">新建机房</h4> 22 </div> 23 <div class="modal-body"> 24 25 <form class="form-horizontal" id='add-form'> 26 <input type='hidden' name="table_name" value='idc'> 27 <div class="form-group"> 28 <label class="col-sm-4 control-label">机房名</label> 29 <div class="col-sm-8"> 30 <input type="text" name='name' class="form-control" > 31 </div> 32 </div> 33 <div class="form-group"> 34 <label class="col-sm-4 control-label">电话</label> 35 <div class="col-sm-8"> 36 <input type="text" name='mobile' class="form-control" > 37 </div> 38 </div> 39 </form> 40 </div> 41 <div class="modal-footer"> 42 <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> 43 <button type="button" id='add-confirm' class="btn btn-primary">新增</button> 44 </div> 45 </div> 46 </div> 47 </div>
模态窗跳转是通过,data-target="#add-idc-modal"来控制的。
然后jquer通过"add-confirm"来确认提交的信息,然后通过ajax传递给后端增加的信息。
1 $('#add-confirm').click(function(){ 2 var o=$('#add-form').serialize() 3 $.post('/addapi',o,function(res){ 4 res = JSON.parse(res) 5 console.log(res.code) 6 if(res.code==0){ 7 getList() 8 $('#add-idc-modal').modal('hide') 9 $('#add-form')[0].reset() 10 swal('添加成功','','success') 11 }else{ 12 swal(res.msg,'','error') 13 } 14 }) 15 })
serialize 序列化功能,form表单中提交的信息都可以给序列化出来
这里传递给后端的table_name是通过隐藏的input来实现的。
flask代码:
@app.route('/addapi', methods=['POST'])
def addapi():
rev_dict = request.form.to_dict() #转换为字典
rev_tab_name = rev_dict.pop('table_name')
result = db.add(rev_tab_name,rev_dict)
return json.dumps(result)
@app.route('/listapi')
mysql代码:
1 def add(self,table_name,table_val): #table_val格式 : {name=xxx,mobile=wwww} 2 table_key = ','.join(table_val.keys()) 3 key_val = ','.join(["'%s'"%v for v in table_val.values()]) 4 # sql = "insert into %s (%s) values (%s)"%(table_name,col_names,values) 5 sql = "insert into %s (%s) values (%s)"%(table_name,table_key,key_val) 6 self.execute(sql) 7 return {'code':0}
删除某个条目
删除的条目想起初想的是利用username来删除,结果没有实现,结果用id来删除比较方便。
这里之前用过模板继承,可否来记得,定义一个大的模板layout2.html,layout2.html中定义了大的框架块。然后其他的小选项中可以来引用这个大的块,然后还可以在添加自己的内容,这里html的代码能模块话,当然页面中相同的利用jquey操作也可以模块化,定义到layout2.html中,下面就利用模块化来删除某个条目。
layout2.html 中代码
1 function bind_delete(selector,table_name){ 2 $(document).on('click',selector,function(){ 3 var id = $(this).attr('data-id') #获取id的值 4 5 swal({ 6 title: "confirm", 7 text: "确认删除"+$(this).attr('data-name')+"?", 8 type: "warning", 9 showCancelButton: true, 10 confirmButtonColor: "#DD6B55", 11 confirmButtonText: "yes", 12 closeOnConfirm: false 13 }, 14 function(){ 15 $.post('/deleteapi',{id:id,table_name:table_name},function(res){ 16 if(res=='ok'){ 17 18 swal('success','','success') 19 getList() 20 }else{ 21 swal('error','删除失败','error') 22 } 23 }) 24 }); 25 }) 26 27 }
idc.html 中的代码:
bind_delete('.del-btn','idc') #直接就一行调用函数的代码,传入需要操作的对象及表名字。
flask 代码:
1 def deleteapi(): 2 table_name = request.form.get('table_name') 3 row_id = request.form.get('id') 4 print '=='*40 5 print row_id 6 result = db.remove(table_name,row_id) 7 return 'ok'
mysql 代码:
1 def remove(self,table_name,row_id): 2 sql = 'delete from %s where id=%s'%(table_name,row_id) 3 print '++++'*30 4 print sql 5 res = self.execute(sql) 6 print res 7 return res
期间遇到一个数据库报错的问题
1 def execute(self,sql): 2 # error handle 3 try: 4 print self.cursor.execute(sql) 5 return self.cursor 6 except mysql.OperationalError as e: 7 # connect 8 print e 9 print 'reconnect db' 10 self.connect() 11 time.sleep(1) 12 return self.execute(sql)
执行的时候一直输出, reconnect db.....
排查的方法是mysql的报错打印出来, as e: 再print e.
实现左侧图标点击高亮
前端代码:
<ul id='navsidebar' class="nav nav-sidebar">
<li ><a href="/user">用户名</a></li>
<li><a href="/idc">机房</a></li>
<li><a href="/pc">机器</a></li>
var path = location.pathname var $page = $('#navsidebar').find('[href="'+path+'"]') $page.parent().addClass('active') $('#page-header-title').html($page.html())
思路:通过location.pathname,获取当前在哪个目录下,然后通过find,找到这个元素,在对其父层做active处理,便实现了这个效果
小知识点
1 <script> 2 $(document).ready(function () { 3 $('#test').html('hello python') 4 }) 5 6 $(function () { 7 $('#test').html("hello python ") 8 }) 9 10 </script>
这两种写法是相同的,第二种是第一种的简写。
下拉框的实现
机房>>>新增机器>>>IDC 下拉框的实现
可以通过下拉框来选择机房。
1 <div class="form-group"> 2 <label class="col-sm-2 control-label">IDC</label> 3 <div class="col-sm-8"> 4 <select name='idc' class="form-control" id = 'add-idc-select'> 5 </select> 6 </div> 7 </div>
通过jquery & ajax去调用数据库的数据库返回。
1 function getidc(){ 2 $.getJSON('/listapi?table_name=idc',function(res){ 3 var option_str = '' 4 $.each(res,function(i,v){ 5 option_str += '<option value='+v[0]+'>'+v[1]+'</option>' 6 }) 7 $('#add-idc-select').html(option_str) 8 }) 9 } 10 11 getidc()
时间选择器
基于的css/js
href="/static/bootstrap-datetimepicker.css"
src='/static/bootstrap-datetimepicker.js'
这两个是基于jquery的,得写到jquery的下面。
代码:
$('#add-pc-time,#update-pc-time').datetimepicker({
startView: 2,
minView: 2,
format:"yyyy-mm-dd"
})
update后端数据在前端展示
实现的功能,点击update后会把后端的数据展示的表里面,修改后,点击更新会提交到后端。
第一步:
首先要把后端的内容在前端展示,设计的思路是吧需要展示的内容都绑定到update键上面。然后再利用each循环,展示到table当中
update button需要绑定的内容:
1 function getList(){ 2 $.getJSON('/listapi?table_name=pc',function(res){ 3 var html_str = '' 4 $.each(res,function(i,j){ 5 html_str += '<tr>' 6 html_str += '<td>'+j[7]+'</td>' 7 html_str += '<td>'+j[1]+'</td>' 8 html_str += '<td>'+j[2]+'</td>' 9 html_str += '<td>'+j[3]+'</td>' 10 html_str += '<td>'+j[4]+'</td>' 11 html_str += '<td>'+j[5]+'</td>' 12 html_str += '<td>'+j[6]+'</td>' 13 html_str += '<td>' 14 html_str += '<button class="del-btn btn btn-danger btn-xs" data-name="'+j[1]+'" data-id="'+j[0]+'">delete</button>' 15 html_str += '<button class="update-btn btn btn-success btn-xs" data-id="'+j[0]+'" data-ip="'+j[1]+'" data-memory="'+j[2]+'" data-disk="'+j[3]+'" data-idc="'+j[4]+'" data-buy_time="'+j[5]+'" data-comment="'+j[6]+'" >update</button>' 16 html_str += '</td>' 17 html_str += '</tr>' 18 }) 19 //console.log([$('#pc-list').html()]) 20 21 render_table('my-pc-table',html_str) 22 23 }) 24 }
点击update后内容的回调:
1 $(document).on('click','.update-btn',function(){ 2 $('#update-pc-modal').modal('show') //跳出模态框 3 // console.log($(this).data()) //定义的都是data-XX开头,所以通过$(this).date()就可以获取这些关键字 4 $.each($(this).data(),function(i,v){ 5 //console.log(i,'----->',v) 6 $('#update-pc-form').find('[name='+i+']').val(v) //通过name选择器来选择,然后做显示。 7 8 }) 9 })
下一步就是更新后的内容返回给后端了:
update的代码与add相似,就是把数据序列化后传递给后端:
$('#update-pc-btn').click(function(){ var o=$('#update-pc-form').serialize() alert(o) $.post('/updateapi',o,function(res){ res = JSON.parse(res) console.log(res) console.log(res.code) if(res.code==0){ getList() $('#update-pc-modal').modal('hide') swal('更新成功','','success') }else{ swal(res.msg,'','error') } }) })
然后flask接受传递来的数据,
1 def updateapi(): 2 allval = request.form.to_dict() 3 print '%%'*40 4 table_name = allval.pop('table_name') 5 print table_name 6 print allval 7 res = db.update(table_name,allval) 8 if res == 'ok': 9 return '{"code":0}' 10 else: 11 return '{"code":1}'
执行数据库:
1 def update(self,table_name,args): 2 arg_id = args.pop('id') 3 temp = ['%s="%s"'%item for item in args.items()] //循环的item是个元组的形式 4 update_str = ','.join(temp) 5 sql = 'update %s set %s where id=%s'%(table_name,update_str,arg_id) 6 db.execute(sql) 7 return 'ok'
用户登录基础的session实现
1 #coding=utf-8 2 from flask import Flask,render_template,request,redirect,session 3 from dbutil import db 4 import json 5 #from dbutil import db 6 7 app = Flask(__name__) 8 app.secret_key='1234567890' 9 10 @app.route('/') 11 def index(): 12 #res = db.list('users') 13 #return json.dumps(res) 14 return redirect('/idc') 15 16 @app.route('/login', methods=['POST','GET']) 17 def login(): 18 if request.method == "GET": 19 if 'username' in session: #判断session是否已经存在了 20 return redirect('/idc') 21 else: 22 return render_template('login.html') 23 if request.method == "POST": 24 username = request.form.get('username') 25 password = request.form.get('password') 26 res = db.list('user',where={'username':username,'password':password}) 27 print 'res===>',res 28 if len(res) == 0: 29 return 'login error' 30 else: 31 session['username'] = username #增加到session里面 32 return redirect('/idc') 33 34 @app.route('/logout') 35 def logout(): 36 del session['username'] #退出删除session 37 return redirect('/login')
1 def list(self,table_name,col_name='*',where={}): 2 #select * from user where username='admin' and password='admin'; 判断用户是否存在 3 sql = 'select %s from %s'%(col_name,table_name) 4 print 'where',where 5 if where: 6 temp = ' where ' 7 temp += 'and'.join([' %s="%s" '%item for item in where.items()]) 8 sql += temp 9 print 'sql',sql 10 print sql 11 res = self.execute(sql) 12 return res.fetchall()
##数据库中查找用户是否存在!!
flask login_required 用法:
定义一个方法:
def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if not session.get('username'): return redirect('/login') return f(*args, **kwargs) return decorated_function
然后每个url都去@调用这个方法就实现了seesion的引用
@app.route('/secret_page') @login_required def secret_page(): pass
另外还可以定义一次,在请求调用这个,不必每个页面都去调用了,@app.before_request,后面做详细学习。
token的使用
token 主要用于调用api接口时候的验证。
基本的原理如同下面的小例子:
首先我们需要基于一种加密算法,如 base64 ,可正反互解的。然后根据根据客户传递过来的信息,如用户名、密码、role,再加上过期时间做加密,然后把这串字符作为token传给客户,下次访问的时候url中带上token,服务器端做解密,然后核对用户信息,时间是否过期等,如果正常则返回给客户所需要的信息。
1 #!/usr/bin/python 2 #coding: utf-8 3 4 import base64 5 import time 6 7 secret_key = 'woqunianmailegebiao' 8 9 10 def create_token(user,role): #加密过程 11 temp = '%s|%s|%s|%s'%(secret_key,user,role,int(time.time()+60*60*12)) 12 return base64.b64encode(temp) 13 14 #print create_token('reboot','admin') 15 def verify_token(token): #解密验证过程 16 temp = base64.b64decode(token).split('|') 17 if len(temp) ==4: 18 secret,user,role,expire_time = temp 19 if secret == secret_key: 20 if int(expire_time) > time.time(): 21 return {'code':0,'user':user,'role':role} 22 else: 23 return {'code':20,'msg':'expire time !!'} 24 else: 25 return {'code':10,'mes':"wrong key"} 26 else: 27 return {'code':1,'msg':'wrong token'} 28 29 #print verify_token('d29xdW5pYW5tYWlsZWdlYmlhb3xyZWJvb3R8YWRtaW58MTUwMTYyNDYwMQ==')
如果通过登录的方式,就把token传递给前端了,前端可以使用自己生成url的方法来使请求的url带上token的字段
首先定义一个myget的方法,来对$.get请求的内容做填丛
1 //定义api请求的方法 2 $.myget = function(url,data,fn){ 3 if(localStorage.token){ 4 $.get(url+'?access_token'+localStorage.token,data,fn) 5 }else{ 6 location.href='/login' 7 } 8 }
然后在请求listapi时,代替传统的$.api
1 function getList(){ 2 3 $.myget('/listapi','table_name=idc',function(res){ 4 var res = JSON.parse(res) 5 //$.getJSON('/listapi?table_name=idc',function(res){ 6 var html_str = '' 7 $.each(res,function(i,j){ 8 html_str += '<tr>' 9 html_str += '<td>'+j[3]+'</td>' 10 html_str += '<td>'+j[1]+'</td>' 11 html_str += '<td>'+j[2]+'</td>' 12 html_str += '<td><button class="del-btn btn btn-danger btn-xs" data-name="'+j[1]+'" data-id="'+j[0]+'">delete</button></t 13 d>' 14 html_str += '</tr>' 15 }) 16 //console.log([$('#idc-list').html()]) 17 18 render_table('my-idc-table',html_str) 19 20 }) 21 } 22 23 getList()
绘图展示
获取内存信息的土著方法:
1 import time 2 3 4 def get_mem(): 5 with open('/proc/meminfo') as f: 6 total = f.readline().split()[1] 7 free = f.readline().split()[1] 8 ava = f.readline().split()[1] 9 buf = f.readline().split()[1] 10 cache = f.readline().split()[1] 11 print ('free %s ava %s')%(free,ava) 12 13 14 while True: 15 get_mem() 16 time.sleep(2)
利用psutil的升华版
#!/usr/bin/python
# coding: utf-8
import psutil as ps
import time
def get_mem():
mem_info = ps.virtual_memory().available
print mem_info
while True:
get_mem()
time.sleep(2)
psutil 模块