[py]web框架本质-自动动手实现一个mvc框架

来源:互联网 发布:php网页爬虫 编辑:程序博客网 时间:2024/06/05 16:52

py实现服务器

存在问题:
访问http://127.0.0.1:8003/bbs不可以
http://127.0.0.1:8003/new可以.

#!/usr/bin/env python# coding=utf-8from wsgiref.simple_server import make_serverdef new():    return "new"def bbs():    return "bbs"urls={    "/new":new,    "/bbs":bbs,}def RunServer(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/html')])    url = environ["PATH_INFO"]    #    # if url=="/new":    #     msg=new()    # elif url=="/bbs":    #     msg=bbs()    # else:    #     msg="404"    # return msg    # if url in urls.keys():    #     msg=urls[url]()    # else:    #     msg="404"    # return msg    for k in urls:        if k==url:            msg=urls["bbs"]()        else:            msg="404"    return msgif __name__ == '__main__':    httpd = make_server('', 8003, RunServer)    print("Serving HTTP on port 8000...")    httpd.serve_forever()

列表试验:
* for i in alis.key()
* for i in alis.value()
* for i in []: 判断是否在列表中

#!/usr/bin/env python# coding=utf-8def show():    return "show info"info={    "name":"maxiaolang",    "age":22,    "show":show,}for k in info:    if k=="show":        msg=info[k]()print msg

简易框架实现–一个文件

#!/usr/bin/env python# coding=utf-8from wsgiref.simple_server import make_serverurls={    "/new":new,    "/bbs":bbs,}def RunServer(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/html')])    url = environ["PATH_INFO"]    if url in urls.keys():        msg=urls[url]()    else:        msg="404"    return "<h1>"+msg+"</h1>"if __name__ == '__main__':    httpd = make_server('', 8003, RunServer)    print("Serving HTTP on port 8000...")    httpd.serve_forever()

毛台框架实现–mvc拆分

架构思想图:
架构图

└─maotai    │  01new.html    │  controller.py    │  controller.pyc    │  start.py    │  urls.py    │  urls.pyc    │  views.py    │  __init__.py    │    └─views
C:\Users\Administrator\Desktop\py\maotai>type controller.py#!/usr/bin/env python# coding=utf-8def new():    # return "new"    f=open("./01new.html",'r')    data = f.read()    f.close()    return datadef bbs():    return "bbs"C:\Users\Administrator\Desktop\py\maotai>type urls.py#!/usr/bin/env python# coding=utf-8import controllerurls={    "/new":controller.new,    "/bbs":controller.bbs,}C:\Users\Administrator\Desktop\py\maotai>type start.py#!/usr/bin/env python# coding=utf-8from wsgiref.simple_server import make_serverfrom urls import urlsdef RunServer(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/html')])    url = environ["PATH_INFO"]    if url in urls.keys():        msg=urls[url]()    else:        msg="404"    return "<h1>"+msg+"</h1>"if __name__ == '__main__':    httpd = make_server('', 8003, RunServer)    print("Serving HTTP on port 8000...")    httpd.serve_forever()

实现动态获取数据-显示时间

import osimport time...def bbs():    f=open(os.path.join("views","bbs.html"),'r')    data = f.read()    f.close()    data=data.replace("{{item}}", str(time.time()))    return data
bbs.html<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>bbs</title>    <style>        .box{            width: 200px;            height: 200px;            background-color: pink;        }    </style></head><body><h1>now: {{item}}</h1><div class="box">this is bbs</div></body></html>

实现动态获取数据-配合jinj2

pip install jinja2.pip/pip.conf[global]index-url = http://mirrors.aliyun.com/pypi/simple/[install]trusted-host=mirrors.aliyun.com
# contorller.pydef bbs():    f = open(os.path.join("views", "bbs.html"), 'r')    data = f.read()    f.close()    tmp=Template(data)    data=tmp.render(name="maotai",user_list=['aaron','bob','cristin','danny'])    return data.encode("utf-8")
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>bbs</title>    <style>        .box{            width: 200px;            height: 200px;            background-color: pink;        }    </style></head><body><h1>name: {{ name }}</h1><ul>    {% for user in user_list %}    <li>{{ user }}</li>    {% endfor %}</ul></body></html>

tornado

武老师tornado快速入门

tornado返回字符串

#!/usr/bin/env python# coding=utf-8import tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        self.write("Hello, world")# 路由系统 路由映射application = tornado.web.Application([    (r"/index", MainHandler),])if __name__ == "__main__":    application.listen(8888)    tornado.ioloop.IOLoop.instance().start()

tornado返回html

#!/usr/bin/env python# coding=utf-8import tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        self.render("bbs.html")application = tornado.web.Application([    (r"/index", MainHandler),])if __name__ == "__main__":    application.listen(8888)    tornado.ioloop.IOLoop.instance().start()
# bbs.html<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>bbs</title>    <style>        .box{            width: 200px;            height: 200px;            background-color: pink;        }    </style></head><body><div class="box"></div></ul></body></html>

tornano使用setting设置绝对路径

C:\Users\Administrator\Desktop\py\d2\tornado>type tornado_demo.py#!/usr/bin/env python# coding=utf-8import tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        # self.write("Hello, world")        self.render("bbs.html")    def post(self):        self.write("hello post")settings = {    "template_path":"template", #模板路径配置}application = tornado.web.Application([    (r"/index", MainHandler),],    ** settings)if __name__ == "__main__":    application.listen(8888)    tornado.ioloop.IOLoop.instance().start()C:\Users\Administrator\Desktop\py\d2\tornado>type template/bb.html
# template/bbs.html<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>bbs</title>    <style>        .box{            width: 200px;            height: 200px;            background-color: pink;        }    </style></head><body><div class="box"></div></ul></body></html>

tornado静态路径配置

存放css js等. 该框架需要对这些文件做路径配置,不然html找不到js等.

settings = {    "template_path":"template",    "static_path":"static",}# 新建static,将common.css存放在其下
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>bbs</title>    <link rel="stylesheet" href="static/common.css"> //这里就可以找到了    <style>        .box{            width: 200px;            height: 200px;            background-color: pink;        }    </style></head><body><div class="box"></div></ul></body></html>

静态文件设置前缀和静态文件缓存

settings = {    'template_path': 'template',    'static_path': 'static',    'static_url_prefix': 'sss',}<link rel="stylesheet" href="sss/static/common.css">
<link href="{{static_url("commons.css")}}" rel="stylesheet" />

表单提交

class MainHandler(tornado.web.RequestHandler):    def get(self):        # self.write("Hello, world")        self.render("bbs.html")    def post(self,*args,**kwargs):        print "post"        self.write("hello post")
<body><form  method="post" action="/index">    <input type="text">    <input type="submit" value="提交"></form></ul></body>

后台获取前台提交的数据

    def post(self,*args,**kwargs):        name = self.get_argument("age")        print name        self.write("hello post")
<form  method="post" action="/index">    <input type="text" name="age">    <input type="submit" value="提交"></form>

展示数据-静态数组

    def get(self):        # self.write("Hello, world")        self.render("bbs.html",names=[1,2,3,4,5])    def post(self,*args,**kwargs):        name = self.get_argument("name")        INPUT_LIST.append(name)        self.write("hello post")
<h1>添加数据</h1><form  method="post" action="/index">    <input type="text" name="name">    <input type="submit" value="提交"></form><h1>展示数据</h1>    {% for name in names %}    <li>{{ name }}</li>    {% end %}</ul>

展示数据-展示前台添加的数据

INPUT_LIST=[]class MainHandler(tornado.web.RequestHandler):    def get(self):        # self.write("Hello, world")        self.render("bbs.html",names=INPUT_LIST)    def post(self,*args,**kwargs):        name = self.get_argument("name")        INPUT_LIST.append(name)        self.render("bbs.html", names=INPUT_LIST)
<h1>添加数据</h1><form  method="post" action="/index">    <input type="text" name="name">    <input type="submit" value="提交"></form><h1>展示数据</h1>    {% for name in names %}    <li>{{ name }}</li>    {% end %}</ul>

通过get提交数据&展示数据

<body><h1>添加数据</h1><form  method="get" action="/index">    <input type="text" name="username">    <input type="text" name="password">    <input type="submit" value="提交"></form><h1>展示数据</h1>    {% for name in names %}    <li>{{ name }}</li>    {% end %}</ul></body>

通过浏览器提交数据

# 通过浏览器提交数据http://127.0.0.1:8888/index?username=123&password=123456

通过以下代码,可以打印出提交的数据

INPUT_LIST=[]class MainHandler(tornado.web.RequestHandler):    def get(self):        # self.write("Hello, world")        print self.get_argument("username")        print self.get_argument("password")        self.render("bbs.html",names=INPUT_LIST)

通过get方法实现数据的提交和展示

INPUT_LIST=[]class MainHandler(tornado.web.RequestHandler):    def get(self):        # self.write("Hello, world")        username= self.get_argument("username")        password= self.get_argument("password")        INPUT_LIST.append(username)        INPUT_LIST.append(password)        self.render("bbs.html",names=INPUT_LIST)        # self.render("bbs.html")

一个小的注意事项:
如果不加参数?username=123&password=456直接访问:http://127.0.0.1:8888/index
会报错:

WARNING:tornado.general:400 GET /index (127.0.0.1): Missing argument usernameWARNING:tornado.access:400 GET /index (127.0.0.1) 1.00ms
    def get(self):        username= self.get_argument("username",None)        password= self.get_argument("password",None)        if username and password: # 如果不为空才添加            INPUT_LIST.append(username)            INPUT_LIST.append(password)        self.render("bbs.html",names=INPUT_LIST)

向前端传值

    def get(self):        # self.write("Hello, world")        username= self.get_argument("username",None)        password= self.get_argument("password",None)        if username and password:            INPUT_LIST.append(username)            INPUT_LIST.append(password)        self.render("bbs.html",npm="NPM",names=INPUT_LIST)
<h1>{{ npm }}</h1>

模板判断语句

<h1>展示数据</h1>    {% for name in names %}        {% if name == "maotai" %}            <li style="color:yellow">{{ name }}</li>        {% else %}            <li>{{ name }}</li>        {% end %}    {% end %}</ul>

模板函数uimethod

添加uimethod.py

def func(self,arg):    return arg.lower()

设置主程序关联函数

import uimethod as mtsettings = {    "template_path":"template",    "static_path":"static",    "ui_methods": mt,}

模板里调用

<h1>{{func(npm)}}</h1>

模板函数uimodule

新建uimodule.py

from tornado.web import UIModulefrom tornado import escapeclass custom(UIModule):    def render(self, *args, **kwargs):        return "12345"
import uimodule as mdsettings = {    "template_path":"template",    "static_path":"static",    "ui_methods": mt,    "ui_modules": md,}
<h3>{% module custom() %}</h3>

模板语法小结:

模板语言支持
+ {{}}
+ {%%}
+ 自定义方式 uimethod uimodule

tornado内置函数

Tornado默认提供的这些功能其实本质上就是 UIMethod 和 UIModule

escape: tornado.escape.xhtml_escape 的別名xhtml_escape: tornado.escape.xhtml_escape 的別名url_escape: tornado.escape.url_escape 的別名json_encode: tornado.escape.json_encode 的別名squeeze: tornado.escape.squeeze 的別名linkify: tornado.escape.linkify 的別名datetime: Python 的 datetime 模组handler: 当前的 RequestHandler 对象request: handler.request 的別名current_user: handler.current_user 的別名locale: handler.locale 的別名_: handler.locale.translate 的別名static_url: for handler.static_url 的別名xsrf_form_html: handler.xsrf_form_html 的別名

escape 转义
handler == self

静态文件缓存效果图
image

settings = {    'template_path': 'template',    'static_path': 'static',    'static_url_prefix': '/sss/', # 如果使用了static_url,这里会自动添加, 如果没用static_url,在调用css时候,需要手动在html里prefix这个,如 <style rel="stylesheet" href='sss/static/common.css'></style>}

前端页面调用 static_url(),做静态缓存

<style rel="stylesheet" href='{{ static_url("common.css") }}'></style><script src='{{ static_url("maotai.js")}}'></script>

模板引擎的实质

整个过程其实就是将一个html转换成一个函数,并为该函数提供全局变量,然后执行该函数!!
image

test.py

#!/usr/bin/env python# coding=utf-8namespace= {"name":"maotai","data":[11,22,33]}code = '''def hellocode():return "name %s,age %d"%(name,data[0])'''func = compile(code,'<string>',"exec")exec(func,namespace)result=namespace['hellocode']()print (result)

简言之理解:

通过namespace执行函数,而在执行函数前,函数所使用的全局变量已经定义了.

namespace= {"name":"maotai","data":[11,22,33],'hellocode':def hellocode():return "name %s,age %d"%(name,data[0])}