前戏篇:Web框架推导
Web框架本质
web框架本质上可以看成是一个功能强大的socket服务端,用户的浏览器可以看成是拥有可视化界面的socket客户端。两者通过网络请求实现数据交互,学者们也可以从架构层面上先简单的将Web框架看做是对前端、数据库的全方位整合
纯手工撸web框架
import socket
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn, addr = server.accept()
data = conn.recv(1024)
print(data)
# 服务端响应的数据需要符合HTTP响应格式
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
# 将客户端请求相关数据转成字符串
data_str = data.decode('utf-8')
# 研究发现可以采用字符串切片
current_path = data_str.split(' ')[1]
# 根据后缀的不同返回不同的内容
if current_path == '/index':
conn.send(b'hello index')
elif current_path == '/login':
conn.send(b'hello login')
else:
with open(r'ershou.html','rb') as f:
conn.send(f.read())
conn.close()
基于wsgiref模块搭建web框架
基础代码
from wsgiref.simple_server import make_server
def run(env,response): # 这里定义什么函数名都可以
"""
:param env: 请求相关的所有数据,以字典的形式呈现
:param response: 响应相关的所有数据
:return: 返回给浏览器的数据
"""
print(env)
response('200 OK', []) # 响应首行 响应头(固定编写无需掌握)
# 从env中取
current_path = env.get('PATH_INFO')
if current_path == '/index':
return [b'index']
elif current_path == '/login':
return [b'login']
return [b'404 error']
if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run)
'''会实时监听127.0.0.1:8080地址 只要有客户端来了
都会交给run函数处理(加括号触发run函数的运行)'''
server.serve_forever() # 启动服务端
升级代码
from wsgiref.simple_server import make_server
def index():
return 'index'
def login():
return 'login'
def error():
return '404 error'
urls = [
('/index', index),
('/login', login),
]
def run(env,response):
response('200 OK',[])
current_path = env.get('PATH_INFO')
func = None
for url in urls:
if current_path == url[0]:
func = url[1]
break
if func:
res = func()
else:
res = error()
return [res.encode('utf-8')]
if __name__ == '__main__':
server = make_server('127.0.0.1',8080,run)
server.serve_forever()
路由拆分协议流程
-views.py(存储视图函数)
# 存储视图函数(存放后端业务逻辑) def index(): return 'index' def login(): return 'login' def error(): return '404 error' # 动态网页设计 # 获取进入网站的时间 import datetime def get_time(): current_time = datetime.datetime.now().strftime('%Y-%m-%d %X') # 如何将后端获取到的数据"传递"给html文件 with open(r'templates/01 get_time.html', 'r', encoding='utf-8') as f: data = f.read() data = data.replace('shijianbiao',current_time) # 在后端html页面处理好之后再返回前端 return data # 将一个字典传递给html文件,并且可以在html文件上方便快捷的操作字典数据 from jinja2 import Template def get_dict(): user_dic = {'username':'jiang','age':110,'gender':'male','hobby':'sleep'} with open(r'templates/02 get_dict.html','r',encoding='utf-8') as f: data = f.read() tmp = Template(data) res = tmp.render(user=user_dic) # 给get_dict.html传递了一个值 页面上通过变量名user就能够拿到user_dict return res import pymysql def get_user(): # 去数据库中获取数据 传递给html页面 借助于模版语法 发送给浏览器 conn = pymysql.connect( host = '127.0.0.1', port = 3306, user = 'root', password = 'root', db='wsgiref01', charset = 'utf8', autocommit = True ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select * from user_info' affect_rows = cursor.execute(sql) data_list = cursor.fetchall() # [{},{},{}] # 将获取到的数据传递给html文件 with open(r'templates/get_data.html','r',encoding='utf-8') as f: data = f.read() tmp = Template(data) res = tmp.render(user_list=data_list) # 给get_dict.html传递了一个值 页面上通过变量名user就能够拿到user_dict return res if __name__ == '__main__': get_user(111)
-urls.py(存储路由与视图函数的对应关系)
# 存储路由与视图函数的对应关系 from views import * urls = [ ('/index',index), ('/login',login), ('/get_time',get_time), ('/get_dict',get_dict), ]
-server.py(存储启动及分配diamagnetic)
# 存储启动及分配代码 from wsgiref.simple_server import make_server from views import * from urls import urls def run(env, response): print(env) response('200 OK', []) # 响应首行 响应头 current_path = env.get('PATH_INFO') # 定义一个变量 存储匹配到的函数名 func = None for url in urls: if current_path == url[0]: func = url[1] break if func: res = func() else: res = error() return [res.encode('utf-8')] if __name__ == '__main__': server = make_server('127.0.0.1', 8080, run) server.serve_forever() # 启动服务端
-templates文件夹(模板文件 存储html文件)
# 存储html文件 mytime.html <body> <h1>我真的是一个html文件</h1> datetime </body> get_dict.html <body> <h1>我是一个页面</h1> {{ user }} {{ user.get('username')}} {{ user.age }} {{ user['hobby'] }} </body> get_data.html <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h1 class="text-center">用户数据</h1> <table class="table table-hover table-striped"> <thead> <tr> <th>ID</th> <th>username</th> <th>password</th> <th>hobby</th> </tr> </thead> <tbody> <!-- [{},{},{},{},{}]--> {% for user_dict in user_list %} <tr> <td>{{ user_dict.id}}</td> <td>{{ user_dict.username}}</td> <td>{{ user_dict.password}}</td> <td>{{ user_dict.hobby}}</td> </tr> {% endfor%} </tbody> </table> </div> </div> </div> </body>
-static文件夹(静态文件 存储html页面所需静态资源)
模板语法之jinja2模块
# 模板语法可以将后端的内容传递给HTML页面,实现前端数据的动态展现 第三方模块需要先下载再使用 pip3 install jinja2 """模版语法是在后端起作用的""" # 模版语法(非常贴近python语法) {{ user }} {{ user.get('username')}} {{ user.age }} {{ user['hobby'] }}
{% for user_dict in user_list %} <tr> <td>{{ user_dict.id}}</td> <td>{{ user_dict.username}}</td> <td>{{ user_dict.password}}</td> <td>{{ user_dict.hobby}}</td> </tr> {% endfor%}
web框架请求流程图
""" wsgiref模块 1、请求来的时候解析http格式的数据 封装成大字典 2、响应走的时候给数据打包成符合http格式 再返回给浏览器 """
主要关键字
urls.py 后缀与函数名对应关系 ('/index',register) 后缀专业名词称之为'路由' 函数名专业名词称之为'视图函数' urls.py专业名词称之为'路由层' views.py 专门编写业务逻辑代码 可以是函数 也可以是类 函数专业名词称之为'视图函数' 类专业名词称之为'视图类' views.py专业名词称之为'视图层' templates文件夹 专门存储html文件 html文件专业名词称之为'模板文件' templates文件夹专业名词称之为'模板层' static文件夹 专门存储静态文件资源 页面所需css文件、js文件、图片文件、第三方文件可统称为'静态资源'