原创仅供学习,转载请注明出处

前情回顾

前一篇写了​​Python web框架开发 - 模板功能 - 肥仔们的爱好​​关于模板功能。

功能需求 - 添加数据

那么下面继续深入,考虑一下如何添加数据到table中呢?

要做这个交互效果的话,就要改改原始的HTML页面了。

修改如下:


Python web框架开发 - 模板功能 - 添加数据_正则匹配


增加两个添加按钮,方便后续点击发送添加的请求。代码如下:

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<table border="1px">
<thead>
<th>肥仔id</th>
<th>肥仔名称</th>
<th>肥仔爱好</th>
<th>肥仔职业</th>
<th>肥仔居住地</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>胖子老板</td>
<td>斗地主</td>
<td>小卖部老板</td>
<td>西九龙</td>
<td><button type="submit"><a href="fat_boy_add/1.html">添加</a></button></td>
</tr>
<tr>
<td>2</td>
<td>肥仔白</td>
<td>吃槟榔、打dota</td>
<td>挨踢男</td>
<td>铜锣湾</td>
<td><button type="submit"><a href="fat_boy_add/2.html">添加</a></button></td>
</tr>
</tbody>
</table>
</body>
</html>

点击添加会发送GET请求如下:


Python web框架开发 - 模板功能 - 添加数据_html_02


​fat_boy_add/1.html​​ 其中这里的 1 代表的就是这条数据的 id ,用于后续查询数据后,进行数据插入的条件。

那么先把该页面放入项目中,尝试访问看看。

编写fat_boy_add路由,提供页面访问


Python web框架开发 - 模板功能 - 添加数据_数据_03


# fat_boy_add
@route("fat_boy_add")
def fat_boy_add(file_path):
print("file_path=",file_path)

# 创建Connection连接
conn = connect(host='localhost', port=3306, user='root', password='', database='test_db', charset='utf8')
# 获得Cursor对象
cs1 = conn.cursor()
# 执行select语句,并返回受影响的行数:查询一条数据
count = cs1.execute('select * from fatboy_hobby;')
# 打印受影响的行数
print("查询到%d条数据:" % count)

# 需要拼接的HTML内容
"""
<tr>
<td>1</td>
<td>胖子老板</td>
<td>斗地主</td>
<td>小卖部老板</td>
<td>西九龙</td>
<td><button type="submit"><a href="fat_boy_add/1.html">添加</a></button></td>
</tr>
"""
content = ""

for i in range(count):
# 获取查询的结果
result = cs1.fetchone()
# 打印查询的结果
print(result)
# 获取查询的结果
print("肥仔名称=%s" % result[0])
print("肥仔爱好=%s" % result[1])
print("肥仔职业=%s" % result[2])
print("肥仔居住地=%s" % result[3])
content += """
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td><button type="submit"><a href="fat_boy_add/%s.html">添加</a></button></td>
</tr>
""" % (result[0],result[1],result[2],result[3],result[4],result[0])
# print("content",content.encode("utf-8"))

# 关闭Cursor对象
cs1.close()
conn.close()

file_path = re.sub(r".py", ".html", file_path)
with open(file_path,"rb") as f:
# html_content = f.read()
html_content = str(f.read().decode("utf-8"))

# 使用正则匹配替换<{content}>

ret = re.sub(r"<{content}>", content, html_content)

# print("html_content=",ret)

# 返回html内容
return ret.encode("utf-8")

测试运行看看:


Python web框架开发 - 模板功能 - 添加数据_html_04


好了,这里是可以正常访问的,但是有个问题,尝试能否访问添加按钮的页面。


Python web框架开发 - 模板功能 - 添加数据_数据_05


这里由于超链接访问的是 ​​fat_boy_add/1.py​​ 的路径,这个路径在原来的匹配规则是不无法对应出函数的。


Python web框架开发 - 模板功能 - 添加数据_数据_06


修改匹配函数的规则

那么按照现在的请求url来看,主要是要匹配这几种url路径,如下:

  • ./html/index.py
  • ./html/fat_boy_add/1.py

要求都只要匹配出 ​​index​​​ 和 ​​fat_boy_add​​ 的函数名即可。

下面来测试编写一下正则规则:

In [1]: import re

In [2]: index_path = "./html/index.py"

In [3]: fat_boy_add_path = "./html/fat_boy_add/1.py"

## 首先按照原来的匹配一次
In [34]: ret = re.match(r"./html/[^.]+",index_path).group()

In [35]: ret
Out[35]: './html/index'

## 使用二次正则匹配到 / 为止的分组内容,就是index函数名了。
In [41]: re.match(r"./html/([^/]+)",ret).group(1)
Out[41]: 'index'

## 可以看到,匹配到 点 之前的数据,那么下面要对该结果进行二次正则,匹配到 / 之前的就是函数名了。
In [42]: ret = re.match(r"./html/[^.]+",fat_boy_add_path).group()

## 使用二次匹配到 / 为止的分组内容
In [43]: re.match(r"./html/([^/]+)",ret).group()
Out[43]: './html/fat_boy_add'

## 查看分组就是 fat_boy_add的函数名了。
In [44]: re.match(r"./html/([^/]+)",ret).group(1)
Out[44]: 'fat_boy_add'

In [45]:

将正则匹配应用到代码中看看。


Python web框架开发 - 模板功能 - 添加数据_数据_07


那么下面来测试一下:


Python web框架开发 - 模板功能 - 添加数据_html_08


访问index.py路径是正常的,再来试试其他的路径:


Python web框架开发 - 模板功能 - 添加数据_正则匹配_09


访问fat_boy_add.py也是正常的,尝试点击添加再来访问一下:


Python web框架开发 - 模板功能 - 添加数据_正则匹配_10


修正fat_boy_add/1.py请求的打开页面


Python web框架开发 - 模板功能 - 添加数据_数据_11


再次测试访问看看:


Python web框架开发 - 模板功能 - 添加数据_数据_12


好了,到了这里这个添加的请求也是能够正常返回页面了。那么下一步要实现的功能就是根据发过来路径中的id,插入一条同样内容的数据。

获取id如下路径: ​​./html/fat_boy_add/1.py​​ 那么这个 id 就是 1

根据路径传递过来的id,进行数据插入

首先使用正则匹配出id出来先,测试如下:

In [45]: import re

In [46]: file_path = "./html/fat_boy_add/1.py"

In [47]: re.match(r"./html/fat_boy_add/\d.py",file_path).group()
Out[47]: './html/fat_boy_add/1.py'

In [48]: re.match(r"./html/fat_boy_add/(\d).py",file_path).group(1)
Out[48]: '1'

In [49]:

好了,有了id的值之后,就可以首先写个插入的SQL语句。

查询当前表里的数据:


Python web框架开发 - 模板功能 - 添加数据_html_13

Python web框架开发 - 模板功能 - 添加数据_数据_14


insert into fatboy_hobby
select null,name,hobby,professional,address from fatboy_hobby where id=1;

执行之后的表数据如下:


Python web框架开发 - 模板功能 - 添加数据_数据_15


那么下面添加数据的功能实现就基本清楚了,实现思路大致如下:

  • 使用正则匹配出id的数值
  • 根据id查询出来的结果,插入表中即可

代码实现如下:


Python web框架开发 - 模板功能 - 添加数据_数据_16

Python web框架开发 - 模板功能 - 添加数据_html_17


实现效果如下:


Python web框架开发 - 模板功能 - 添加数据_正则匹配_18

Python web框架开发 - 模板功能 - 添加数据_html_19


好了,写到这里已经实现了添加数据的功能了。

相信写到这里,应该也清楚如何去写删除了,也是根据获取的id,来执行删除即可。

完整代码如下:

fat_boy_add.html

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<body>
<table border="1px">
<thead>
<th>肥仔id</th>
<th>肥仔名称</th>
<th>肥仔爱好</th>
<th>肥仔职业</th>
<th>肥仔居住地</th>
</thead>
<tbody>
<tr>
<{content}>
</tbody>
</table>
</body>
</html>

framwork.py

import re
from pymysql import *

# 设置路由对应的字典
route_dict = dict()
"""
route_dict = {
"index" : index,
"page_about" : page_about,
}
"""
def route(url):
def set_route(func):
# 设置字典映射
route_dict[url] = func
def call_func(file_path):
return func(file_path)
return call_func
return set_route

# index页面
@route("index")
def index(file_path):
file_path = re.sub(r".py", ".html", file_path)
with open(file_path,"rb") as f:
return f.read()

# page_about页面
@route("page_about")
def page_about(file_path):
file_path = re.sub(r".py", ".html", file_path)
with open(file_path,"rb") as f:
return f.read()

# fat_boy页面
@route("fat_boy")
def fat_boy(file_path):
# 创建Connection连接
conn = connect(host='localhost', port=3306, user='root', password='', database='test_db', charset='utf8')
# 获得Cursor对象
cs1 = conn.cursor()
# 执行select语句,并返回受影响的行数:查询一条数据
count = cs1.execute('select * from fatboy_hobby;')
# 打印受影响的行数
print("查询到%d条数据:" % count)

# 需要拼接的HTML内容
"""
<tr>
<td>1</td>
<td>胖子老板</td>
<td>斗地主</td>
<td>小卖部老板</td>
<td>西九龙</td>
</tr>
<tr>
<td>2</td>
<td>肥仔白</td>
<td>吃槟榔、打dota</td>
<td>挨踢男</td>
<td>铜锣湾</td>
</tr>
"""
content = ""

for i in range(count):
# 获取查询的结果
result = cs1.fetchone()
# 打印查询的结果
print(result)
# 获取查询的结果
print("肥仔名称=%s" % result[0])
print("肥仔爱好=%s" % result[1])
print("肥仔职业=%s" % result[2])
print("肥仔居住地=%s" % result[3])
content += """
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
</tr>
""" % (result[0],result[1],result[2],result[3],result[4])
print("content",content.encode("utf-8"))

# 关闭Cursor对象
cs1.close()
conn.close()

file_path = re.sub(r".py", ".html", file_path)
with open(file_path,"rb") as f:
# html_content = f.read()
html_content = str(f.read().decode("utf-8"))

# 使用正则匹配替换<{content}>

ret = re.sub(r"<{content}>", content, html_content)

print("html_content=",ret)

# 返回html内容
return ret.encode("utf-8")

# fat_boy_add
@route("fat_boy_add")
def fat_boy_add(file_path):
print("file_path=",file_path)

# 获取插入数据的选择 id
id = re.match(r"./html/fat_boy_add/(\d).py", file_path).group(1)

# 创建Connection连接
conn = connect(host='localhost', port=3306, user='root', password='', database='test_db', charset='utf8')
# 获得Cursor对象
cs1 = conn.cursor()

# 插入数据
insert_sql = """
insert into fatboy_hobby
select null,name,hobby,professional,address from fatboy_hobby where id=%s;
""" % id
count = cs1.execute(insert_sql)

#打印受影响的行数
print(count)

# 提交之前的操作,如果之前已经之执行过多次的execute,那么就都进行提交
conn.commit()

# 执行select语句,并返回受影响的行数:查询一条数据
count = cs1.execute('select * from fatboy_hobby;')
# 打印受影响的行数
print("查询到%d条数据:" % count)

# 需要拼接的HTML内容
"""
<tr>
<td>1</td>
<td>胖子老板</td>
<td>斗地主</td>
<td>小卖部老板</td>
<td>西九龙</td>
<td><button type="submit"><a href="fat_boy_add/1.html">添加</a></button></td>
</tr>
"""
content = ""

for i in range(count):
# 获取查询的结果
result = cs1.fetchone()
# 打印查询的结果
print(result)
# 获取查询的结果
print("肥仔名称=%s" % result[0])
print("肥仔爱好=%s" % result[1])
print("肥仔职业=%s" % result[2])
print("肥仔居住地=%s" % result[3])
content += """
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td><button type="submit"><a href="%s.py">添加</a></button></td>
</tr>
""" % (result[0],result[1],result[2],result[3],result[4],result[0])
# print("content",content.encode("utf-8"))


# 关闭Cursor对象
cs1.close()
conn.close()

# file_path = re.sub(r".py", ".html", file_path)
file_path = "./html/fat_boy_add.html"
with open(file_path,"rb") as f:
# html_content = f.read()
html_content = str(f.read().decode("utf-8"))

# 使用正则匹配替换<{content}>

ret = re.sub(r"<{content}>", content, html_content)

# print("html_content=",ret)

# 返回html内容
return ret.encode("utf-8")

# 支撑WGSI协议
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=UTF-8')])
# 接受需要打开的文件路径
print("动态file_path= ", environ['REQUEST_URI'])

# 使用正则匹配路径中的函数方法
try:
# func_name = re.match(r"\./html/([^.]+)",environ['REQUEST_URI']).group(1)
## 第一次正则匹配到 小数点 . 的为止
ret = re.match(r"\./html/([^.]+)",environ['REQUEST_URI']).group()
## 第二次正则匹配到 斜杠 / 为止
func_name = re.match(r"./html/([^/]+)",ret).group(1)
except Exception as e:
print("匹配不上,%s" % e)
else:
response_body = route_dict[func_name](environ['REQUEST_URI'])

return response_body

webserver.py

#coding=utf-8
from socket import *
import re
import multiprocessing
import time
import framework
import sys

class WebServer:

def __init__(self,server_port):

# 创建套接字
self.server_socket = socket(AF_INET, SOCK_STREAM)
# 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口
self.server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 设置服务端提供服务的端口号
self.server_socket.bind(('', server_port))
# 使用socket创建的套接字默认的属性是主动的,使用listen将其改为被动,用来监听连接
self.server_socket.listen(128) #最多可以监听128个连接

def start_http_service(self):
# 开启while循环处理访问过来的请求
while True:
# 如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务
# client_socket用来为这个客户端服务
# self.server_socket就可以省下来专门等待其他新的客户端连接while True:
client_socket, clientAddr = self.server_socket.accept()
# handle_client(client_socket)
# 设置子进程
new_process = multiprocessing.Process(target=self.handle_client,args=(client_socket,))
new_process.start() # 开启子进程
# 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的
client_socket.close()

def handle_client(self,client_socket):
"""为一个客户端服务"""
# 接收对方发送的数据
recv_data = client_socket.recv(1024).decode("utf-8") # 1024表示本次接收的最大字节数
# 打印从客户端发送过来的数据内容
#print("client_recv:",recv_data)
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)

# 返回浏览器数据
# 设置内容body
# 使用正则匹配出文件路径
print("------>",request_header_lines[0])
print("file_path---->","./html/" + re.match(r"[^/]+/([^\s]*)",request_header_lines[0]).group(1))
ret = re.match(r"[^/]+/([^\s]*)",request_header_lines[0])
if ret:
file_path = "./html/" + ret.group(1)
if file_path == "./html/":
file_path = "./html/index.html"
print("file_path *******",file_path)

# 判断file_path是否py文件后缀,如果是则请求动态资源,否则请求静态资源
if file_path.endswith(".py"):

# framework.application(client_socket)
# 支撑WGSI协议的调用方式
environ = {}
environ['REQUEST_URI'] = file_path # 设置需要打开的文件路径
response_body = framework.application(environ, self.start_response)
# 设置返回的头信息header
# 1.拼接第一行HTTP/1.1 200 OK + 换行符内容
response_headers = "HTTP/1.1 " + self.application_header[0] + "\r\n"
# 2.循环拼接第二行或者多行元组内容:Content-Type:text/html
for var in self.application_header[1]:
response_headers += var[0]+":"+var[1] + "\r\n"
# 3.空一行与body隔开
response_headers += "\r\n"
# 4.打印看看header的内容信息
print("response_header=")
print(response_headers)

# 设置返回的浏览器的内容
client_socket.send(response_headers.encode("utf-8"))
client_socket.send(response_body)

else:
# 请求静态资源
try:
# 设置返回的头信息 header
response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源
response_headers += "\r\n" # 空一行与body隔开
# 读取html文件内容
file_name = file_path # 设置读取的文件路径
f = open(file_name,"rb") # 以二进制读取文件内容
response_body = f.read()
f.close()
# 返回数据给浏览器
client_socket.send(response_headers.encode("utf-8")) #转码utf-8并send数据到浏览器
client_socket.send(response_body) #转码utf-8并send数据到浏览器
except:
# 如果没有找到文件,那么就打印404 not found
# 设置返回的头信息 header
response_headers = "HTTP/1.1 404 not found\r\n" # 200 表示找到这个资源
response_headers += "\r\n" # 空一行与body隔开
response_body = "<h1>sorry,file not found</h1>"
response = response_headers + response_body
client_socket.send(response.encode("utf-8"))

def start_response(self,status,header):
self.application_header = [status,header]
print("application_header=",self.application_header)

def main():
# 通过sys.argv来获取服务端的端口号
# server_port = int(sys.argv[1])
server_port = 7788

webserver = WebServer(server_port)
webserver.start_http_service()

if __name__ == "__main__":
main()


Python web框架开发 - 模板功能 - 添加数据_数据_20