mini mysql_02- web-mini框架添加路由、MySQL(二)

本篇在上篇的基础上为其增设路由功能,同时将上篇中的数据库中数据备份添加进去。

一、装饰器

在之前有介绍过为一个函数不改变源代码不改变原函数的调用方式下为其增设附加功能,需要用到装饰器,而在该上篇的web-mini框架中每当服务器发送动态资源请求过来时,我们需要做if判断,那么我们可不可以省去这繁琐的步骤呢?

1.1 通过闭包来实现装饰器:

#为函数附加新功能 - 计算运算时长

importtimedeftimmer(func):def wrapper(*args,**kwargs):

start_time=time.time()

ret= func(*args,**kwargs)

end_time=time.time()print("spend time --> %s"%(end_time -start_time))returnretreturnwrapper

@timmer#等价于 ==》test = timmer(test)

deftest(num):

time.sleep(1)print("in the test --> %s"%num )return num*num +1ret= test(8)print(ret)

注1:装饰器在原函数在调用之前就以及开始装饰了。即写上@timmer时test1 = timmer(test)就开始执行。下面我们介绍一种由类实现的装饰器:

1.2 由类实现的装饰器

classTest(object):"""定义一个装饰器类"""

def __init__(self,func):

self.func=funcdef __call__(self,*args,**kwargs):print("在此为函数附加新功能")

ret= self.func(*args,**kwargs)returnret

@Test#get_str = Test(get_str),相当于将get_str传入创建实例对象

defget_str(num):print("in the get_str-->%s"%num)return "hello world!"get_str()#Test(get_str)() ,必须有call魔法方法,实则运行实例的__call__方法

这种由类实现的装饰器,其效果与由闭包实现的装饰器效果几乎一样,但是由于进行一次装饰,需创建一个实例对象,即每次需要开辟一个内存空间,存放着实例属性、方法以及类的中方法的指针等,比较浪费资源,即 杀鸡用牛刀;

1.3 带参数的装饰器

def set_level(level_num): #用来接收参数

def set_func(func): #装饰器函数

def call_func(*args,**kwargs):if level_num = 1:print("设置权限1")elif level_num = 2:print("设置权限2")else:print("你个瓜皮,没有这个权限验证")

ret= func(*args,**kwargs)returnretreturncall_funcreturnset_func

@setlevel(1)deftest1():print("hello world")

@setlevel(2)deftest1():print("妈的个巴子哟")#setlevel(para) --- test1 = set_level(1)#1、首先调用set_level,并且传入参数1, --- test1 = set_level(1)#2、启动装饰器set_func,装饰函数,--- test1 = set_func(test1)

带参数的装饰器:

1、其最外层函数set_level,相当于一个容器用来封装,存储装饰器和一些变量等;而真正的装饰器部分实则为set_func装饰器;

2、进行装饰时:@setlevel(1)实则执行两步操作:

①、首先调用set_level,并且传入参数1, --- test1 = set_level(1) ;

②、启动装饰器set_func,装饰函数,--- test1 = set_func(test1);

二、静态、动态、伪静态URL

目前开发的网站其实真正意义上都是动态网站,只是URL上有些区别,一般URL分为静态URL、动态URL、伪静态URL,他们的区别是什么?

静态URL

静态URL类似 域名/news/2012-5-18/110.html 我们一般称为真静态URL,每个网页有真实的物理路径,也就是真实存在服务器里的。

动态URL

动态URL类似 域名/NewsMore.asp?id=5 或者 域名/DaiKuan.php?id=17,带有?号的URL,我们一般称为动态网址,每个URL只是一个逻辑地址,并不是真实物理存在服务器硬盘里的。

伪静态URL

伪静态URL类似 域名/course/74.html 这个URL和真静态URL类似。他是通过伪静态规则把动态URL伪装成静态网址。也是逻辑地址,不存在物理地址。

三者的优缺点:

1、静态URL:网页打开速度快,SEO最好,但是对于大中型网站而言页面多,修改起来不方便,不便管理;

2、动态URL:由于需要调用框架从数据库中读取数据,故网页打开速度不如静态URL,SEO不如静态URL,但是适合中大型网站,修改页面很方便,因为是逻辑地址,所以占用硬盘空间要比纯静态网站小。

3、伪静态URL:其输入浏览器的形式与静态URL相同,但是确实调用框架读取数据库中的数据来实现的,是相对于前两种的折中方案;URL比较友好,利于记忆;修改页面也十分方便,但是设置麻烦,服务器要支持重写规则,小企业网站或者玩不好的就不要折腾;

二、案例

该实例是在上篇(web-mini框架的基本实现(一))的基础上对其进行修改的,即为其添加路由功能,实现伪静态网页、以及替换成数据库中的数据;

服务端web_server.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

importsocketimportreimportmultiprocessingimporttime#import dynamic.mini_frame

importsysclassWSGIServer(object):def __init__(self, port, app, static_path):#1. 创建套接字

self.tcp_server_socket =socket.socket(socket.AF_INET, socket.SOCK_STREAM)

self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)#2. 绑定

self.tcp_server_socket.bind(("", port))#3. 变为监听套接字

self.tcp_server_socket.listen(128)

self.application=app

self.static_path=static_pathdefservice_client(self, new_socket):"""为这个客户端返回数据"""

#1. 接收浏览器发送过来的请求 ,即http请求

#GET / HTTP/1.1

#.....

request = new_socket.recv(1024).decode("utf-8")#print(">>>"*50)

#print(request)

request_lines=request.splitlines()print("")print(">"*20)print(request_lines)#GET /index.html HTTP/1.1

#get post put del

file_name = ""ret= re.match(r"[^/]+(/[^ ]*)", request_lines[0])ifret:

file_name= ret.group(1)#print("*"*50, file_name)

if file_name == "/":

file_name= "/index.html"

#2. 返回http格式的数据,给浏览器

#2.1 如果请求的资源不是以.py结尾,那么就认为是静态资源(html/css/js/png,jpg等)

if not file_name.endswith(".html"):try:

f= open(self.static_path + file_name, "rb")except:

response= "HTTP/1.1 404 NOT FOUND\r\n"response+= "\r\n"response+= "------file not found-----"new_socket.send(response.encode("utf-8"))else:

html_content=f.read()

f.close()#2.1 准备发送给浏览器的数据---header

response = "HTTP/1.1 200 OK\r\n"response+= "\r\n"

#2.2 准备发送给浏览器的数据---boy

#response += "hahahhah"

#将response header发送给浏览器

new_socket.send(response.encode("utf-8"))#将response ic.mini_frame.applicationbody发送给浏览器

new_socket.send(html_content)else:#2.2 如果是以.py结尾,那么就认为是动态资源的请求

env= dict() #这个字典中存放的是web服务器要传递给 web框架的数据信息

env['PATH_INFO'] =file_name#{"PATH_INFO": "/index.py"}

#body = dynamic.mini_frame.application(env, self.set_response_header)

body =self.application(env, self.set_response_header)

header= "HTTP/1.1 %s\r\n" %self.statusfor temp inself.headers:

header+= "%s:%s\r\n" % (temp[0], temp[1])

header+= "\r\n"response= header+body#发送response给浏览器

new_socket.send(response.encode("utf-8"))#关闭套接

new_socket.close()defset_response_header(self, status, headers):

self.status=status

self.headers= [("server", "mini_web v8.8")]

self.headers+=headersdefrun_forever(self):"""用来完成整体的控制"""

whileTrue:#4. 等待新客户端的链接

new_socket, client_addr =self.tcp_server_socket.accept()#5. 为这个客户端服务

p = multiprocessing.Process(target=self.service_client, args=(new_socket,))

p.start()

new_socket.close()#关闭监听套接字

self.tcp_server_socket.close()defmain():"""控制整体,创建一个web 服务器对象,然后调用这个对象的run_forever方法运行"""

if len(sys.argv) == 3:try:

port= int(sys.argv[1]) #7890

frame_app_name = sys.argv[2] #mini_frame:application

exceptException as ret:print("端口输入错误。。。。。ret:",ret)return

else:print("请按照以下方式运行:")print("python3 xxxx.py 7890 mini_frame:application")return

#mini_frame:application

ret = re.match(r"([^:]+):(.*)", frame_app_name)ifret:

frame_name= ret.group(1) #mini_frame

app_name = ret.group(2) #application

else:print("请按照以下方式运行:")print("python3 xxxx.py 7890 mini_frame:application")returnwith open("./web_server.conf") as f:

conf_info= eval(f.read()) #eval(str)函数很强大,官方解释为:将字符串str当成有效的表达式来求值并返回计算结果

#此时 conf_info是一个字典里面的数据为:

#{

#"static_path":"./static",

#"dynamic_path":"./dynamic"

#}

sys.path.append(conf_info['dynamic_path'])#import frame_name --->找frame_name.py

frame = __import__(frame_name) #返回值标记这 导入的这个模板

app = getattr(frame, app_name) #此时app就指向了 dynamic/mini_frame模块中的application这个函数

#print(app)

wsgi_server= WSGIServer(port, app, conf_info['static_path'])

wsgi_server.run_forever()if __name__ == "__main__":

main()

web_server.py

基于上篇的web_server.py实现了伪静态URL,即读取的URL中的页面filename是以.html结尾即视为动态资源,则调用框架读取数据库中资源替换模板。相当于欺骗浏览器,输入的是静态URL,确实按照动态URL的方式进行处理的;

web_mini框架 mini_frame.py

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

importrefrom pymysql importconnect#方式二:通过定义装饰器,自动添加文件名和函数名的映射关系,实现路由效果

URL_FUNC_DICT=dict()#带参数的装饰器

defroute(url):defget_func(func):

URL_FUNC_DICT[url]=funcdef call_func(*args,**kwargs):

ret=func()returnretreturncall_funcreturnget_funcdefselect_date(sql):

conn= connect(host="localhost",port=3306,database="stock_db",user="root",password= "mysql",charset="utf8")

cs=conn.cursor()

cs.execute(sql)

data_content= cs.fetchall() #得到的是一个元组,里面有很多个元组

cs.close()

conn.close()returndata_content#1.index = route("/index.py")即 index = get_func#2.index = get_func(index)即index = call_func

@route("/index.html")defindex():

with open("./templates/index.html") as f:

content=f.read()

sql= "select * from info;"my_stock_info=select_date(sql)

html_template= """

{0}{1}{2}{3}{4}{5}{6}{7}"""html= ""

for temp inmy_stock_info:

html+= html_template.format(*temp)#print("----->>>{}<<

content= re.sub(r"\{%content%\}", html, content)returncontent

@route("/center.html")defcenter():

with open("./templates/center.html") as f:

content=f.read()

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;"my_stock_info=select_date(sql)#print(mys)

html =""html_template= """

{0}{1}{2}{3}{4}{5}{6}

修改

"""

for temp inmy_stock_info:

html+= html_template.format(*temp)

content= re.sub(r"\{%content%\}", html, content)returncontent#方式一:这种方式通过映射,手动定义字典添加key为文件名:value为对应函数名;#URL_FUNC_DICT = {#"/index.py":index,#"/center.py":center

#}

print(URL_FUNC_DICT)defapplication(env, start_response):

start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])

file_name= env['PATH_INFO']#file_name = "/index.py"

run_func=URL_FUNC_DICT[file_name]returnrun_func()#if file_name == "/index.py":

#return index()

#elif file_name == "/center.py":

#return center()

#else:

#return 'Hello World! 我爱你中国....'

mini_frame.py

基于上篇的 mini_frame.py 实现了添加路由功能、及替换成MySQL数据库中的资源的效果;

over~~~其他部分基本与其他相同~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值