類Flask框架實現html
模板python
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <br>顯示數據<\br> {{id}} {{name}} {{age}} </body> </html>
import re from io import StringIO,BytesIO d = {'id':5,'name':'tom','age':20} class Template: _pattern = '{{([a-zA-Z0-9_]+)}}' regex = re.compile(_pattern) @classmethod def render(cls,template,data:dict): html = StringIO() with open(template,encoding='utf-8') as f: for line in f: start = 0 newline = '' for matcher in cls.regex.finditer(line): newline += line[start:matcher.start()] print(matcher,matcher.group(1)) key = matcher.group(1) tmp = data.get(key,'') newline += str(tmp) start = matcher.end() else: newline += line[start:] html.write(newline) print(html.getvalue()) html.close()#模板渲染 filename = 'index.html' Template.render(filename,d)
jinja2web
文檔 官網 https://jinja.palletsprojects.com/en/2.10.x/ 中文 http://docs.jinkan.org/docs/jinja2/ 安裝 pip install jinja2 pip install MarkupSafe
模板構建正則表達式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Magedu</title> </head> <body> <ul> 顯示數據 {% for id,name,age in userlist %} <li>{{loop.index}},{{id}},{{name}},{{age}}</li> {% endfor %} </ul> 總共{{usercount}}人 </body> </html>
#################加載模板代碼以下示例################### from jinja2 import Environment,PackageLoader,FileSystemLoader # env = Environment(loader=PackageLoader('webarch','templates')) #包加載器 env = Environment(loader=FileSystemLoader('webarch/templates')) template = env.get_template('index.html') userlist = [ (3,'tpm',20), (4,'het',23), (7,'asdf',23), (1,'aasf',18) ] d = {'userlist':userlist,'usercount':len(userlist)} print(template.render(**d))
###############提供模板模塊template.py################## from jinja2 import Environment,PackageLoader,FileSystemLoader env = Environment(loader=PackageLoader('webarch','templates')) #包加載器 # env = Environment(loader=FileSystemLoader('webarch/templates')) #文件系統加載器 def render(name,data:dict): """ 模板渲染 :param name: 去模板目錄搜索此模板名的文件 :param data: 字典數據 :return: HTML字符串 """ template = env.get_template(name) #搜索模塊index.html return template.render(**data)
##############代碼中增長################## #建立Router對象 idx = Router() py = Router('/python') user = Router('/user') #註冊 App.register(idx,py) App.register(user) py.register_preinterceptor(ip) @user.get(r'^/?$') def userhandler(request): userlist = [ (3, 'tpm', 20), (4, 'het', 23), (7, 'asdf', 23), (1, 'aasf', 18) ] d = {'userlist':userlist,'usercount':len(userlist)} return render('index.html',d)
模塊化json
1.建立包webarch 2.template.py模塊移入此包 3.新建web.py模塊,將AttrDict、Router、App類放入其中 4.將路由定義、註冊代碼、handler定義移入webarch/__init__.py中 5.在項目根目錄下,建一個app.py,裏面放入啓動server的代碼。
攔截器interceptorapp
#加入攔截器功能的方式 1、App和Router類直接加入 把攔截器的相關方法、屬性分別添加到相關類中 實現簡單 2、Mixin App和Router類都須要這個攔截器功能,能夠使用Mixin方式、將屬性、方法組合進來,可是,App類攔截器適合使用第二種,可是Router的攔截器是每一個實例不同的,因此使用第一種方式實現
def fn(request:Request) -> Request: pass
def fn(request:Request,response:Response) -> Response: pass
IP攔截框架
#建立Router對象 idx = Router() py = Router('/python') user = Router('/user') #註冊 App.register(idx,py) App.register(user) #ip攔截 def ip(request:Request): print(request.remote_addr,'~~~~~') print(type(request.remote_addr)) if request.remote_addr.startswith('192.'): return request else: return None #返回None將截斷請求 py.register_preinterceptor(ip)
Json支持模塊化
@py.get(r'^/{id}$') def pythonhandler(request): userlist = [ (3, 'tom', 20), (5, 'jerry', 16), (6, 'sam', 23), (8, 'kevin', 18) ] d = {'userlist':userlist,'usercount':len(userlist)} res = Response(json=d) return res
總結函數
完整代碼oop
################webarch/__init__.py##################### from webob import Request,Response #模板 from .template import render from .web import Router,App #建立Router對象 idx = Router() py = Router('/python') user = Router('/user') #註冊 App.register(idx,py) App.register(user) #ip攔截 def ip(request:Request): print(request.remote_addr,'~~~~~') print(type(request.remote_addr)) if request.remote_addr.startswith('192.'): return request else: return None #返回None將截斷請求 py.register_preinterceptor(ip) @idx.get(r'^/$') @idx.route(r'^/{id:int}$') #支持全部方法 def indexhandler(request): id = '' if request.groupdict: id = request.groupdict.id return '<h1>magedu.com{}歡迎你</h1>'.format(id) @py.get(r'^/{id}$') def pythonhandler(request): userlist = [ (3, 'tom', 20), (5, 'jerry', 16), (6, 'sam', 23), (8, 'kevin', 18) ] d = {'userlist':userlist,'usercount':len(userlist)} res = Response(json=d) return res @user.get(r'^/?$') def userhandler(request): userlist = [ (3, 'tpm', 20), (4, 'het', 23), (7, 'asdf', 23), (1, 'aasf', 18) ] d = {'userlist':userlist,'usercount':len(userlist)} return render('index.html',d)
###########webarch/web.py############# import re from webob import Request,Response from webob.exc import HTTPNotFound from webob.dec import wsgify class AttrDict: def __init__(self,d:dict): self.__dict__.update(d if isinstance(d,dict) else {}) def __setattr__(self, key, value): #不容許修改屬性 raise NotImplementedError def __repr__(self): return "<AttrDict {}>".format(self.__dict__) def __len__(self): return len(self.__dict__) class Router: __regex = re.compile(r'/{([^{}:]+):?([^{}:]*)}') TYPEPATTERNS = { 'str':r'[^/]+', 'word':r'\w+', 'int':r'[+-]?\d+', 'float':r'[+-]?\d+\.\d+', 'any':r'.+' } TYPECAST = { 'str':str, 'word':str, 'int':int, 'float':float, 'any':str } def __parse(self,src: str): start = 0 repl = '' types = {} matchers = self.__regex.finditer(src) for i, matcher in enumerate(matchers): name = matcher.group(1) t = matcher.group(2) types[name] = self.TYPECAST.get(t, str) repl += src[start:matcher.start()] #拼接分組前 tmp = '/(?P<{}>{})'.format( matcher.group(1), self.TYPEPATTERNS.get(matcher.group(2), self.TYPEPATTERNS['str']) ) repl += tmp # 替換 start = matcher.end() #移動 else: repl += src[start:] # 拼接分組後的內容 return repl, types #####實例 def __init__(self,prefix:str=''): self.__prefix = prefix.rstrip('/\\') #前綴,例如/product self.__routetable = [] #存四元組,列表,有序的 ##攔截器## self.pre_interceptor = [] self.post_interceptor = [] ##攔截器註冊函數## def register_preinterceptor(self,fn): self.pre_interceptor.append(fn) return fn def register_postinterceptor(self,fn): self.post_interceptor.append(fn) return fn def route(self,rule,*methods): #註冊路由 def wrapper(handler): #/student/{name:str}/xxx/{id:int} ==> '/student/(?P<name>[^/]+/xxx/(?P<id>[+-]\\d+))' pattern,trans = self.__parse(rule) # 用戶輸入規則轉換爲正則表達式 self.__routetable.append( (tuple(map(lambda x:x.upper(),methods)), re.compile(pattern), trans, handler )#(方法元組,預編譯正則對象,類型轉換,處理函數) ) return handler return wrapper def get(self,pattern): return self.route(pattern,'GET') def post(self,pattern): return self.route(pattern,'POST') def head(self,pattern): return self.route(pattern,'HEAD') def match(self,request:Request): #必須先匹配前綴 if not request.path.startswith(self.__prefix): return None ##局部攔截,此Router的請求,開始攔截,處理request## for fn in self.pre_interceptor: request = fn(request) if not request: return None #請求爲None將再也不向後傳遞,截止 #前綴匹配,說明就必須這個Router實例處理,後續匹配不上,依然返回None for methods,pattern,trans,handler in self.__routetable: # not methods表示一個方法都沒有定義,就是支持所有方法 if not methods or request.method.upper() in methods: #前提是以__prefix開頭了,能夠replace,去掉prefix剩下的纔是正則表達式須要匹配的路徑 matcher = pattern.match(request.path.replace(self.__prefix,'',1)) if matcher:#正則匹配 newdict = {} for k,v in matcher.groupdict().items(): newdict[k] = trans[k](v) #動態增長屬性 request.groupdict =AttrDict(newdict)#命名分組組成的字典被屬性化 response = handler(request) ##局部攔截響應,依次攔截,處理響應## for fn in self.post_interceptor: response = fn(request,response) return response class App: _ROUTERS = [] #存儲全部一級對象 ##全局攔截器## PRE_INTERCEPTOR = [] POST_INTERCEPTOR = [] ##全局攔截器註冊函數## @classmethod def register_preinterceptor(cls,fn): cls.PRE_INTERCEPTOR.append(fn) return fn @classmethod def register_postinterceptor(cls,fn): cls.POST_INTERCEPTOR.append(fn) return fn #註冊路由 @classmethod def register(cls,*routers:Router): for router in routers: cls._ROUTERS.append(router) @wsgify def __call__(self, request:Request): ##全局攔截請求## for fn in self.PRE_INTERCEPTOR: request = fn(request) #遍歷_ROUTERS,調用Router實例的match方法,進行匹配 for router in self._ROUTERS: response = router.match(request) ##全局攔截響應## for fn in self.POST_INTERCEPTOR: response = fn(request,response) if response: #匹配返回非None的Router對象 return response raise HTTPNotFound('<h1>你訪問的頁面不存在!</h1>')
#########webarch/template.py############# from jinja2 import Environment,PackageLoader,FileSystemLoader env = Environment(loader=PackageLoader('webarch','templates')) #包加載器 # env = Environment(loader=FileSystemLoader('webarch/templates')) #文件系統加載器 def render(name,data:dict): """ 模板渲染 :param name: 去模板目錄搜索此模板名的文件 :param data: 字典數據 :return: HTML字符串 """ template = env.get_template(name) #搜索模塊index.html return template.render(**data)
###########app.py######### from .web import App from wsgiref.simple_server import make_server if __name__ == '__main__': ip = '127.0.0.1' port= 9999 server = make_server(ip,port,App()) try: server.serve_forever() # server.handle_request() 一次 except KeyboardInterrupt: server.shutdown() server.server_close()
發佈
#######setup.py#### from distutils.core import setup import glob #導入setup函數並傳參 setup( name='webarch', version='0.1.0', description='Python WSGI Web Framework', author='cy', url='https://www.magedu/com', packages=['webarch'], datafiles=glob.glob('webarch/templates/*.html')#返回列表 )