- 一、先写一个web框架,也就是后端服务器
- 二、根据需求一步步接近Django
- 需求一:
- 需求二:根据输入返回html页面
- 基于wsgiref模块实现上面的需求
- 基于wsgiref模块实现需求后代码进行封装
- 进一步对wsgrief实现的功能代码进行拆分(因为代码多后会比较乱,所以将功能拆分成不同的文件)
- 更进一步对wsgrief实现的功能代码进行拆分(考虑当文件比较多的时候,使用文件夹进行划分)
- 动静态网页
- 制作动态网页
- 1、后端获取当前时间展示到html页面上(使用比较low的方法)
- 2、将一个字典传递给html文件 并且可以在文件上方便快捷的操作字典数据(使用模板语法:Jinja2模块)
- 实践:后端获取数据库中的数据进行前端展示
- 总结:jinja2使用
- 自定义简易版本web框架请求流程图
一、先写一个web框架,也就是后端服务器
1、服务端代码
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 如果为空默认为TCP
server.bind(("127.0.0.1",9000))
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.listen(5)
while True:
conn,addr = server.accept()
data = conn.recv(1024)
print(data) #先研究这个data
conn.send(b"HTTP1.1 200 ok\r\n\r\n Hello world") #加http协议的回应头,和回应码,注意\r\n\r\n不能少
conn.close()
2、客户端浏览器访问这个web服务端
访问时加不同的后缀,之后查看服务端
3、查看服务端
"""
b'GET /index HTTP/1.1\r\n
Host: 127.0.0.1:9000\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36\r\n
Sec-Fetch-Dest: document\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n\r\n'
"""
"""
b'GET /login HTTP/1.1\r\n
Host: 127.0.0.1:9000\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36\r\n
Sec-Fetch-Dest: document\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n\r\n'
"""
注意:我们只看圈出来的,那两个/favicon.ico我们不关注
通过服务端接收我们发现,在访问时加的后缀时,后端查看就是圈出来的数据第二个字段
二、根据需求一步步接近Django
需求一:
根据客户端浏览器输入时添加的不同后缀,服务端返回不同的内容
例如:
客户端浏览器输入http://127.0.0.1:9000/index;服务端返回index
实现:
根据一中我们已经直到,浏览器输入的后缀可以在服务端接收的data获取到,就是data的第二个字段;so,服务端接收到data后可以对data字符串进行decode(“utf-8”)解码,之后split切割,搞成列表,这样后缀就是获取到的列表索引为1的元素
代码:
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 如果为空默认为TCP
server.bind(("127.0.0.1",9000))
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.listen(5)
while True:
conn,addr = server.accept()
data = conn.recv(1024)
data=data.decode("utf-8") #字符串
current_path = data.split()[1] #取到后缀
# print(current_path)
#发回应头和回应码
conn.send(b"HTTP1.1 200 ok\r\n\r\n") #和要发的内容分开,分两次发
#拿到路径后进行判断
if current_path == "/index":
conn.send(b"This is index ")
elif current_path == "/login":
conn.send(b"This is login ")
elif current_path == "/":
conn.send(b"hello web ")
else:
conn.send(b"404")
conn.close()
需求二:根据输入返回html页面
代码:
import socket
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 如果为空默认为TCP
server.bind(("127.0.0.1",9000))
server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
server.listen(5)
while True:
conn,addr = server.accept()
data = conn.recv(1024)
data=data.decode("utf-8") #字符串
current_path = data.split()[1] #取到后缀
# print(current_path)
#发回应头和回应码
conn.send(b"HTTP1.1 200 ok\r\n\r\n") #和要发的内容分开,分两次发
#拿到路径后进行判断
if current_path == "/index":
with open("index.html","rb") as f:
conn.send(f.read())
elif current_path == "/login":
conn.send(b"This is login ")
elif current_path == "/":
conn.send(b"hello web ")
else:
conn.send(b"404")
conn.close()
总结:纯手撸版本的不足之处
#不足之处
1.代码重复(服务端代码所有人都要重复写)
2.手动处理http格式的数据 并且只能拿到url后缀 其他数据获取繁琐(数据格式一样处理的代码其实也大致一样 重复写)
3.并发的问题
基于wsgiref模块实现上面的需求
"""
urls.py 路由与视图函数对应关系
views.py 视图函数(后端业务逻辑)
templates文件夹 专门用来存储html文件
"""
# 按照功能的不同拆分之后 后续添加功能只需要在urls.py书写对应关系然后取views.py书写业务逻辑即可
目录:
基于wsgrief模块web框架.py代码:
from wsgiref.simple_server import make_server
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据,和socket一样传输要转成二进制格式
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 拿到路径后进行判断
if current_path == "/index":
with open("index.html", "rb") as f:
return [f.read()] # 写法固定,返回数据用列表包起来
elif current_path == "/login":
return [b"login"]
elif current_path == "/":
return [b"hello web"]
else:
return [b"404 heihei"]
if __name__ == '__main__':
"""
会实时监听127.0.0.1:9000地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
基于wsgiref模块实现需求后代码进行封装
# 开发人员: alias
# 开发时间: 2020/5/22 18:58
# 文件名称: 基于wsgrief模块web框架.py
# 开发工具: PyCharm
from wsgiref.simple_server import make_server
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("index.html", "rb") as f:
return f.read().decode("utf-8") # 先解码,下面return再统一编码
#访问路径为/login的处理函数
def login(env):
return "This is login"
#访问路径不存在的处理函数
def error(env):
return "404"
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
]
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: #这个url就是一个个元组
if current_path == url[0]:
#将url对应的函数名赋值给func
func = url[1]
#匹配到之后结束循环
break
# 判断func是否为None
if func:
res=func(env) #将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res=error(env)
#返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
进一步对wsgrief实现的功能代码进行拆分(因为代码多后会比较乱,所以将功能拆分成不同的文件)
文件说明:
# urls.py:存放url和处理函数的对应关系
# views.py:存放处理函数
# 基于wsgrief模块web框架.py: 入口文件# index.html:处理函数返回给前端的html文件
urls.py
"""
存放url和处理函数的对应关系
"""
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
]
views.py
"""
存放处理函数
"""
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("index.html", "r" , encoding="utf-8") as f:
return f.read()
#访问路径为/login的处理函数
def login(env):
return "This is login"
#访问路径不存在的处理函数
def error(env):
return "404"
基于wsgrief模块web框架.py
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: #这个url就是一个个元组
if current_path == url[0]:
#将url对应的函数名赋值给func
func = url[1]
#匹配到之后结束循环
break
# 判断func是否为None
if func:
res=func(env) #将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res=error(env)
#返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
更进一步对wsgrief实现的功能代码进行拆分(考虑当文件比较多的时候,使用文件夹进行划分)
目录:
首先文件说明:
"""
urls.py 路由与视图函数对应关系
views.py 视图函数(后端业务逻辑)
templates文件夹 专门用来存储html文件
"""
# 按照功能的不同拆分之后 后续添加功能只需要在urls.py书写对应关系然后取views.py书写业务逻辑即可
urls.py
"""
存放url和处理函数的对应关系
"""
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
]
views.py
"""
存放处理函数
"""
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("./templats/index.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径为/login的处理函数
def login(env):
with open("./templats/login.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径不存在的处理函数
def error(env):
return "404"
基于wsgrief模块web框架.py
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: #这个url就是一个个元组
if current_path == url[0]:
#将url对应的函数名赋值给func
func = url[1]
#匹配到之后结束循环
break
# 判断func是否为None
if func:
res=func(env) #将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res=error(env)
#返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
动静态网页
"""
静态网页
页面上的数据是直接写死的 万年不变
动态网页
数据是实时获取的
eg:
1.后端获取当前时间展示到html页面上
2.数据是从数据库中获取的展示到html页面上
"""
制作动态网页
1、后端获取当前时间展示到html页面上(使用比较low的方法)
基于wsgrief模块web框架.py,这个接口文件不变
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: #这个url就是一个个元组
if current_path == url[0]:
#将url对应的函数名赋值给func
func = url[1]
#匹配到之后结束循环
break
# 判断func是否为None
if func:
res=func(env) #将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res=error(env)
#返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
urls.py里面添加路由
from views import *
"""
存放url和处理函数的对应关系
"""
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
("/get_time",get_time),
]
views.py里面添加视图函数
import time
"""
存放处理函数
"""
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("./templates/index.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径为/login的处理函数
def login(env):
with open("./templates/login.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径不存在的处理函数
def error(env):
return "404"
#获取当前时间,展示到前端
def get_time(env):
#先获取当前时间
current_time = time.strftime("%Y-%m-%d %X")
#如何将后端获取到的数据传递给html文件
with open("./templates/mytime.html","r",encoding="utf-8") as f:
data = f.read()
data = data.replace("dadfafdadfa",current_time)
return data
mytime.html:返回的前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>mytime</title>
</head>
<body>
<!--随便写的字符串用于替换成当前时间-->
dadfafdadfa
</body>
</html>
2、将一个字典传递给html文件 并且可以在文件上方便快捷的操作字典数据(使用模板语法:Jinja2模块)
jinja2模块安装方法:
#pip3 install jinja2
目录:
基于wsgrief模块web框架.py,这个接口文件不变
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env, response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok", []) # 响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') # 取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: # 这个url就是一个个元组
if current_path == url[0]:
# 将url对应的函数名赋值给func
func = url[1]
# 匹配到之后结束循环
break
# 判断func是否为None
if func:
res = func(env) # 将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res = error(env)
# 返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1", 9000, run) # 这个函数有个server返回值要接收一下
server.serve_forever() # 启动服务端
urls.py添加路由
from views import *
"""
存放url和处理函数的对应关系
"""
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
("/get_time",get_time),
("/get_dict",get_dict), #添加get_dict路由关系
]
views.py添加视图函数
import time
from jinja2 import Template
"""
存放处理函数
"""
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("./templates/index.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径为/login的处理函数
def login(env):
with open("./templates/login.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径不存在的处理函数
def error(env):
return "404"
#获取当前时间,展示到前端
def get_time(env):
#先获取当前时间
current_time = time.strftime("%Y-%m-%d %X")
#如何将后端获取到的数据传递给html文件
with open("./templates/mytime.html","r",encoding="utf-8") as f:
data = f.read()
data = data.replace("dadfafdadfa",current_time)
return data
#获取字典
def get_dict(env):
#定义一个字典用于发往html文件
user_dic = {"username":"egon","age":18}
with open("./templates/get_dict.html","r",encoding="utf-8") as f:
data = f.read()
tmp = Template(data) # 将html文件读出来的data放入Template之后赋给变量tmp,之后就可以给这个html文件传值了
# 给get_dict.html传递了一个值,get_dict.html页面内部通过变量名user就能拿到user_dic,在get_dict.html页面内部怎么引用见get_dict,html
res = tmp.render(user=user_dic)
return res
get_dict.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>get_dict</title>
</head>
<body>
<!--两个大括号,里面加上视图函数传递过来的变量名,这个变量名就对应那个字典user_dic-->
{{ user }}
<!--可以很方便的控制绑定过来的字典,例如字典取值,有三种方式-->
{{ user.get("username") }}
{{ user.age }}
{{ user["username"] }}
</body>
</html>
浏览器访问
实践:后端获取数据库中的数据进行前端展示
准备一下数据库:
目录:
基于wsgrief模块web框架.py,这个接口文件不变
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env,response):
"""
两个模块加括号调用传过来的参数env,response以及return解释:
:param env:请求相关的所有数据
:param response:响应相关的所有数据
:return:返回给浏览器的数据
"""
# print(env) #根据env的大字典,可以发现,浏览器输入的后缀在大字典中的key为'PATH_INFO'
"""
env是一个大字典,字典包含了请求里面的所有数据,还封装了一些其他数据
(这个工作是wsgrief模块做的,帮我们处理好http格式的数据 封装成了字典,让你更加方便的去操作)
"""
response("200 ok",[]) #响应首行,加响应头[],列表内为空就行
current_path = env.get('PATH_INFO') #取到后缀路径
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls: #这个url就是一个个元组
if current_path == url[0]:
#将url对应的函数名赋值给func
func = url[1]
#匹配到之后结束循环
break
# 判断func是否为None
if func:
res=func(env) #将env一同传给函数接收的好处,功能更加强调,方便函数对字典进行各种操作
else:
res=error(env)
#返回数据
return [res.encode("utf-8")] # 写法固定,返回数据用列表包起来
if __name__ == '__main__':
"""
会实时监听127.0.0.1:8080地址 只要有客户端来了都会交给run函数处理(模块会加括号触发run函数的运行)
注意:在加括号调用run函数的时候模块会自动传入两个参数(env,response)
"""
server = make_server("127.0.0.1",9000,run) #这个函数有个server返回值要接收一下
server.serve_forever() #启动服务端
urls.py添加路由
from views import *
"""
存放url和处理函数的对应关系
"""
#url与函数的对应关系
urls = [
("/index",index),
("/login",login),
("/get_time",get_time),
("/get_dict",get_dict),
("/get_user",get_user),
]
views.py添加视图函数
import time
from jinja2 import Template
import pymysql
"""
存放处理函数
"""
#访问路径为/index的处理函数
def index(env):
# 拿到路径后进行判断
with open("./templates/index.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径为/login的处理函数
def login(env):
with open("./templates/login.html", "r", encoding="utf-8") as f:
return f.read()
#访问路径不存在的处理函数
def error(env):
return "404"
#获取当前时间,展示到前端
def get_time(env):
#先获取当前时间
current_time = time.strftime("%Y-%m-%d %X")
#如何将后端获取到的数据传递给html文件
with open("./templates/mytime.html","r",encoding="utf-8") as f:
data = f.read()
data = data.replace("dadfafdadfa",current_time)
return data
#获取字典
def get_dict(env):
#定义一个字典用于发往html文件
user_dic = {"username":"egon","age":18}
with open("./templates/get_dict.html","r",encoding="utf-8") as f:
data = f.read()
tmp = Template(data) # 将html文件读出来的data放入Template之后赋给变量tmp,之后就可以给这个html文件传值了
# 给get_dict.html传递了一个值,get_dict.html页面内部通过变量名user就能拿到user_dic
res = tmp.render(user=user_dic)
return res
def get_user(env):
#去数据库中获取数据,传递给html页面,借助于模板语法 发送给浏览器
# 链接
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='atm_db',
charset='utf8',
# autocommit=True # 自动提交
)
# 游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) #执行完毕返回的结果集以字典显示
# 执行sql语句
sql = 'select * from userinfo'
rows = cursor.execute(sql) # 执行sql语句,返回sql查询成功的记录数目
# 获取数据:
data_list = cursor.fetchall() # [{},{},,,,]列表套字典格式
cursor.close()
conn.close()
#将获取到的数据传递给html文件
with open("./templates/user_info.html", "r", encoding="utf-8") as f:
data = f.read()
tmp = Template(data)
# 给user_info.html传递了一个值,user_info.html页面内部通过变量名user_data就能拿到data_list
res = tmp.render(user_data=data_list)
return res
user_info.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>userinfo</title>
<!-- Bootstrap3 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- Bootstrap3 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- <link rel="stylesheet" href="css/font-awesome.min.css"> -->
<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">用户数据</h1>
<br/>
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="text-center">ID</th>
<th class="text-center">username</th>
<th class="text-center">password</th>
<th class="text-center">balance</th>
<th class="text-center">flow</th>
</tr>
</thead>
<tbody>
{% for user_dict in user_data %}
<tr>
<td>{{ user_dict.id}}</td>
<td>{{ user_dict.username}}</td>
<td>{{ user_dict.password}}</td>
<td>{{ user_dict.balance}}</td>
<td>{{ user_dict.flow}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>>
</div>
</div>
</body>
</html>
浏览器访问效果:
总结:jinja2使用
# pip3 install jinja2 # 安装方法
"""模版语法是在后端起作用的"""
# 模版语法(非常贴近python语法)
{{ user }}
{{ user.get('username')}} #获取值
{{ user.age }}
{{ user['hobby'] }}
# 模板语法支持for循环
{% for user_dict in user_data %}
<tr>
<td>{{ user_dict.id}}</td>
<td>{{ user_dict.username}}</td>
<td>{{ user_dict.password}}</td>
<td>{{ user_dict.balance}}</td>
<td>{{ user_dict.flow}}</td>
</tr>
{% endfor %}
自定义简易版本web框架请求流程图
"""
wsgiref模块做的两件事
1.请求来的时候解析http格式的数据 封装成大字典
2.响应走的时候给数据打包成符合http格式 再返回给浏览器
"""