一、mini-Web框架
1、区分静态和动态资源的请求(使用框架程序处理客户端的动态资源请求操作)
web.py中:
# 把请求.html文件和其他文件的请求进行分离
if not file_name.endswith(".html"):
# 静态请求处理
try:
with open("static" + file_name, "rb") as f:
response_body = f.read()
except:
response_line = "HTTP/1.1 400 NOT FOUND\r\n"
with open("static/404.html", "rb") as f:
response_body = f.read()
else:
# 动态请求处理
response_status, response_headers, response_body = appclication(file_name)
response_line = "HTTP/1.1 %s\r\n" % response_status
response_header = "Content-Type: text/html;charset=utf-8\r\n"
for i in response_headers:
response_header += i[0] + ":" + i[1] + "\r\n"
response_body = response_body.encode("utf-8")
framework.py中:
def appclication(file_name):
"""按照要求返回对应的相应内容给服务器"""
if file_name == "/index.html":
return index()
elif file_name == "/center.html":
return center()
else:
return not_found()
2、首页的初步展示
framework.py中
def index():
"""处理/index.html的请求"""
status="200 OK"
response_header = [("Server", "python12/2.0")]
with open("templates/index.html", "r") as f:
response_body = f.read()
return status, response_header, response_body
web.py中:
如果发现css样式在页面中不显示,则把响应头中的 Content-Type: text/html;charset=utf-8,去掉(或者换成text/css, 但是要考虑其他种类文件,比较繁琐)
3、首页数据展示,实现模板替换功能
def index():
"""处理/index.html的请求"""
status="200 OK"
response_header = [("Server", "python12/2.0")]
with open("templates/index.html", "r") as f:
response_body = f.read()
# 连接数据库,获取数据
conn1 = pymysql.connect(host="localhost", port=3306, user="root", password="mysql", database="stock_db", charset="utf8")
cs = conn1.cursor()
sql = "select * from info;"
cs.execute(sql)
data = cs.fetchall()
cs.close()
conn1.close()
# 准备模板
html = ''
for i in data:
html+="""<tr><td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td><input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="000007"></td>
</tr>""" % i
# 替换模板
response_body = response_body.replace("{%content%}", html)
return status, response_header, response_body
4、路由字典的实现
route_dict={
"/index.html": index,
"/center.html": center
}
def appclication(file_name):
"""按照要求返回对应的相应内容给服务器"""
# 接下来项目中每添加一个页面或者有一个动态资源的请求,就会多一个if判断
# 为了便于管理, 我们把请求路径和执行的函数之间的对应关系抽取出来,体现在一个路由字典中
try:
return route_dict[file_name]()
except:
return not_found()
5、装饰器方式的添加路由
先解答以下两个题目
题目1(带参数的装饰器):
定义一个装饰器,对函数使用装饰器实现简单的动态验证, 对f1函数添加 验证1, 对f2函数添加 验证2
题目2:
先定义一个空列表lst,用装饰器实现以下功能:
每次在这个python文件中定义任意一个函数的时候,列表都会自动添加一个元素,这个元素就是刚刚定义的这个函数的引用,
即:通过 lst[0]() 可以调用刚才第一个函数,通过 lst[1]() 可以调用刚才第二个函数
# 上面的方式如果项目中每添加一个页面或者有一个动态资源的请求,仍旧需要手动往route_dict字典中添加元素
# 使用装饰器装饰对应的函数,可以让每一个对应关系在函数定义的时候自动生成
# 接下来使用装饰器来自动生成这个路由字典
route_dict = dict()
def route(url):
def route_(func):
route_dict[url] = func
def fn_in(*args, **kwargs):
return func()
return fn_in
return route_
@route("/index.html")
def index():
"""处理/index.html的请求"""
...
@route("/center.html")
def center():
"""处理/center.html的请求"""
...
6、个人中心数据接口的开发(center)
上面我们书写的index函数,是直接返回整个页面给前端,
其实,框架程序还可以开发数据接口,为客户端程序提供数据服务,即,我们后端只把数据从数据库中查询出来,返回这些数据提供给前端,而前端可以做ajax请求来获取这些数据,在ajax的success回调函数中把这些数据填到中模板中
前端center.html页面中:
<script>
$(document).ready(function(){
$.ajax({
url:"/center_data.html",
type:"GET",
dataType:"JSON",
success:function(resp){
console.log(resp)
}
})
});
</script>
framework.py中添加一个接口函数center_data,在center_data函数中:
@route("/center_data.html")
def center_data():
"""返回/center_data.html的请求"""
status = "200 OK"
response_header = [("Server", "python12/2.0")]
# 1、连接数据库, 查询和获取前端需要展示的数据
conn1 = pymysql.connect(host="localhost", port=3306, user="root", password="mysql", database="stock_db",
charset="utf8")
cs = conn1.cursor()
sql = "select i.code,i.short,i.chg,i.turnover,i.price,i.highs,f.note_info from info as i inner join focus as f on i.id=f.info_id;"
cs.execute(sql)
data = cs.fetchall() # 是一个元组
cs.close()
conn1.close()
# 2、把数据转成json格式的字符串,并返回这个json格式的字符串
# 注意:元组的格式不是json格式,而data是一个元组,我们需要把它处理成字典,再转json字符串
data_list = list()
for i in data:
data_list.append({
"code": i[0],
"short": i[1],
"chg": i[2],
"turnover": i[3],
"price": str(i[4]),
"highs": str(i[5]),
"note_info": i[6]
})
json_str = json.dumps(data_list,ensure_ascii=False) # 把data_list转成json格式的字符串
# ensure_ascii=False即不使用ascii编码,可以在前端完好地显示中文
return status, response_header, json_str
总结————个人中心数据接口的开发步骤:
# 1、连接数据库, 查询和获取前端需要展示的数据
# 2、把数据转成json格式的字符串,并返回这个json格式的字符串
7、前端获取到接口后,请求这个接口的数据,填入页面中
在center.html的ajax的success回调函数中:
for(var i=0;i<resp.length; i++){
$tr = $('<tr><td>'+ resp[i].code +'</td><td>'+ resp[i].short +'</td><td>'+ resp[i].chg +'</td><td>'+ resp[i].turnover +'</td><td>'+ resp[i].price +'</td><td>'+ resp[i].highs +'</td><td>'+ resp[i].note_info +'</td><td><a type="button" class="btn btn-default btn-xs" href="/update/000007.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a></td><td><input type="button" value="删除" id="toDel" name="toDel" systemidvaule="000007"></td></tr>');
$("table").append($tr);
}
二、带有参数的装饰器
def fn(num):
def fn_(func):
def fn_in(*args, **kwargs):
print(“验证%s” % num)
func()
return fn_in
return fn_
@fn("A") # 相当于 f1 = fn("A")(f1)
def f1():
print("-----f1-----")
@fn("B") # 相当于 f1 = fn("B")(f1)
def f2():
print("-----f2-----")
f1()
f2()
结论:
如果装饰器需要带参数,在原先书写的闭包装饰器外边再套一层函数,并在这个函数的最后返回次外层函数的引用