• Python入门自学进阶-Web框架——42、Web框架了解-bottle、flask


    WEB框架的三大组件:路由系统、控制器(含模板渲染)、数据库操作

    微型框架:依赖第三方写的socket,WSGI,  本身功能少

    安装:
    pip install bottle


    pip install flask

    安装flask,同时安装了MarkupSafe、Werkzeug、Jinja2、itsdangerous。
    Werkzeug是Python的WSGI规范的实用函数库。使用广泛,基于BSD协议,是Flask使用的底层WSGI库;
    itsdangerous是flask中引用的一个第三方包,用来解决生成token等网络安全问题;
    MarkupSafe为 Python 实现 XML/HTML/XHTML 标记安全字符串;
    Jinja2是一个模板语言,是一个现代的、设计友好的、依照django模板的python模板语言;

    pip install tornado

    已经安装过。

    Bottle:

    一个程序文件完成整个网站:

    1. from bottle import template,Bottle
    2. root = Bottle()
    3. @root.route('/hello/')
    4. # 装饰器,定义了URL,即/hello/这个url由index这个函数来处理,就是路由系统
    5. def index():
    6. return "Hello World!"
    7. root.run(host='localhost', port=8080)
    8. # 这里就是启动webserver服务器,然后等待请求

    运行整个Python程序:

    浏览器端请求:

    上面的路由(即装饰器)是静态路由,还可以使用动态路由:

    @root.route('/wiki/')
    def
     callback(pagename):
        ...

    pagename作为参数变量名,匹配字符串。

    @root.route('/object/')
    def
     callback(id):
        ...
    id是一个int型的参数变量名。

    @root.route('/show/')
    def
     callback(name):
       ...
    name是一个正则表达式参数变量。

    @root.route('/static/')
    def
     callback(path):
        
    return static_file(path, root='static')
    定义路径,类似Django中的静态文件路径,主要是定义文件在服务器存储中的位置。

    root指定的是项目中的一个目录,这里指定了项目中的static,在这个目录下有testcss.css文件,可以访问:

    修改一下:

    如果root为'static'不变,还可以这样访问:

    对于路由对应的函数,除了返回字符串,还可以使用模板:

    1. @root.route('/hello/')
    2. # 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
    3. def index():
    4. # return "Hello World!"
    5. return template('Hello {{name}}!',name="小花")

    对于template(),除了像上面直接在其中写模板外,还可以直接指定一个模板文件,如

    return template(‘index.html’)

    创建index.html文件。这里要注意的是默认bottle找模板的路径,在bottle中有如下配置变量

    TEMPLATE_PATH = ['./', './views/'],即默认模板查找顺序是先在项目根目录,然后是views目录,我们可以添加自己定义的目录
    

    最终程序:

    1. from bottle import template,Bottle,static_file
    2. import bottle
    3. bottle.TEMPLATE_PATH.append('./templates/')
    4. root = Bottle()
    5. # 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
    6. @root.route('/hello/')
    7. def index():
    8. print(bottle.TEMPLATE_PATH)
    9. # return "Hello World!"
    10. # return template('Hello {{name}}!',name="小花")
    11. return template("index.html")
    12. @root.route('/sta/')
    13. def callback(path):
    14. return static_file(path,root='static')
    15. root.run(host='localhost', port=8080)

    运行程序后,打印的TEMPLATE_PATH为:['./', './views/', './templates/'],但是却找不到模板文件:

    经过反复的测试,查找资料,这个问题我个人的理解是:

    这个路径是linux系统的路径,在windows系统下失去效果,windows系统下,需要添加windows的绝对路径,使用os.path.abspath(os.path.join(os.path.dirname(__file__), "views")来获取windows下的绝对路径:

    1. from bottle import run,template,Bottle,TEMPLATE_PATH
    2. import os
    3. app = Bottle()
    4. TEMPLATE_PATH.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "templates")))
    5. TEMPLATE_PATH.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "views")))
    6. print(TEMPLATE_PATH)
    7. @app.route('/')
    8. @app.route('/hello/')
    9. def index(name='default'):
    10. return template('hello.html',name=name)
    11. run(app,host='localhost',port=8080)

    这时的TEMPLATE_PATH为:

    ['D:\\website\\bottlepro\\templates', './', './views/', 'D:\\website\\bottlepro\\views']

    这时再访问,就没有问题了。

    请求方法路由

    @root.route('/hello/', method='POST')
    def index():
        ...
     
    @root.get('/hello/')
    def index():
        ...
     
    @root.post('/hello/')
    def index():
        ...
     
    @root.put('/hello/')
    def index():
        ...
     
    @root.delete('/hello/')
    def index():
        ...

    一个简单的登陆:

    1. from bottle import template,Bottle,static_file,TEMPLATE_PATH,request,redirect
    2. import os
    3. TEMPLATE_PATH.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'templates')))
    4. root = Bottle()
    5. # 装饰器,定义了URL,即/hello/这个url由index这个函数来处理
    6. @root.route('/login/',method=['GET','POST'])
    7. def login():
    8. if request.method == "GET":
    9. return template('login.html')
    10. else:
    11. # v = request.forms # POST的数据都保存
    12. # v = request.query # GET发来的请求数据
    13. # v = request.body # POST发来的请求数据
    14. u = request.forms.get('user')
    15. p = request.forms.get('pwd')
    16. print(u,p)
    17. return redirect('/index/')
    18. @root.route('/index/')
    19. def index():
    20. return template('index.html')
    21. @root.route('/sta/')
    22. def callback(path):
    23. return static_file(path,root='static')
    24. root.run(host='localhost', port=8080)
    25. # 这里就是启动webserver服务器,然后等待请求
    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1>Bottle登录h1>
    9. <form action="/login/" method="post">
    10. <input type="text" name="user" placeholder="用户名">
    11. <input type="password" name="pwd" placeholder="密码">
    12. <input type="submit" value="提交">
    13. form>
    14. body>
    15. html>

    Bottle中的request其实是一个LocalReqeust对象,其中封装了用户请求的相关信息:

    request.headers     :    请求头信息

    request.query         :    get请求信息

    request.forms         :     post请求信息

    request.files            :    上传文件信息

    request.params       :     get和post请求信息

    request.GET             :     get请求信息

    request.POST           :     post和上传信息

    request.cookies        :     cookie信息     

    request.environ        :     环境相关相关

    bottle的模板,在使用for循环遍历列表生成

    • 时的问题:

      1. @root.route('/index/')
      2. def index():
      3. user_list = [
      4. {'id': 1, 'name': 'root1', 'age': 18},
      5. {'id': 2, 'name': 'root2', 'age': 19},
      6. {'id': 3, 'name': 'root3', 'age': 20},
      7. {'id': 4, 'name': 'root4', 'age': 21},
      8. ]
      9. return template('index.html', user_list=user_list)

      模板index.html:

      1. <body>
      2. {{user_list}}
      3. <hr/>
      4. <ul>
      5. % for item in user_list :
      6. <li>{{item}}<li/>
      7. % end
      8. ul>
      9. body>

      预想的是这样:

      实际是这样:

      多出来的这些空行,都是

    • ::marker
    • ,为何会多产生这些标签??怎么去掉?希望高手指点一二。

      Flask:

      基本框架与Bottle差不多,如下:

      1. from flask import Flask
      2. app = Flask(__name__)
      3. @app.route('/index/')
      4. def index():
      5. return "hello world!"
      6. if __name__ == "__main__":
      7. app.run()

      启动后:

      默认是在5000端口。访问:

      在Flask()中,可以对静态文件和模板路径进行配置:相关参数如下

      默认模板路径就是templates,

      这个不像Bottle,项目下创建了templates,就可以直接找到。

      传递参数:

      1. @app.route('/index/')
      2. def index():
      3. # return "hello world!"
      4. return render_template('flaskindex.html',k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})

      模板:

      1. html>
      2. <html lang="en">
      3. <head>
      4. <meta charset="UTF-8">
      5. <title>Titletitle>
      6. head>
      7. <body>
      8. <h1>Flask indexh1>
      9. {{k1}}
      10. {{k2}}
      11. <hr/>
      12. <ul>
      13. {% for item in k2 %}
      14. <li>{{item}}li>
      15. {% endfor %}
      16. ul>
      17. {{k3}}
      18. <hr/>
      19. {% for k,v in k3.items() %}
      20. {{k}}--{{v}}<br>
      21. {% endfor %}
      22. body>
      23. html>

      还可以传递函数:

      模板中:要在变量后加上小括号

      Flask的动态路由方式:

      • @app.route('/user/')
      • @app.route('/post/')
      • @app.route('/post/')
      • @app.route('/post/')
      • @app.route('/login', methods=['GET', 'POST'])

      DEFAULT_CONVERTERS = {
          'default':          UnicodeConverter,
          'string':           UnicodeConverter,
          'any':              AnyConverter,
          'path':             PathConverter,
          'int':              IntegerConverter,
          'float':            FloatConverter,
          'uuid':             UUIDConverter,
      }

      与bottle一样,也有方法请求路由,即在路由中增加“method=”参数

      对于Http请求,Flask会讲请求信息封装在request中(werkzeug.wrappers.BaseRequest),提供的如下常用方法和字段以供使用:

      request.method
      request.args
      request.form
      request.values
      request.files
      request.cookies
      request.headers
      request.path
      request.full_path
      request.script_root
      request.url
      request.base_url
      request.url_root
      request.host_url
      request.host

      Flask中使用cookie:使用make_response函数包装render_template,生成的对象有set_cookie方法。先导入make_response

      1. @app.route('/index/')
      2. def index():
      3. # return "hello world!"
      4. # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
      5. obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
      6. obj.set_cookie('usern','xiaohua')
      7. return obj

      Flask中重定向:redirect

      url_for(别名),这里的别名就是函数名,不需要在route中单独定义

      Flask中使用session,先导入session,from flask import session

      要使用session,需要先配置一个SECRET_KEY,在Flask对象上设置,设置后才能在函数中使用:session['key']=value的方式

      1. from flask import Flask,render_template,make_response,session,request,redirect,url_for
      2. app = Flask(__name__)
      3. app.config.update(SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/') # 要使用session,必须设置这个参数
      4. def myfun():
      5. @app.route('/index/')
      6. def index():
      7. # return "hello world!"
      8. # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
      9. obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
      10. obj.set_cookie('usern','xiaohua')
      11. return obj
      12. @app.route('/login/',methods=['GET','POST'])
      13. def login():
      14. if request.method =='POST':
      15. session['user'] = request.form.get('user') # 设置session内容
      16. url = url_for('redirectaliastest')
      17. return redirect(url)
      18. else:
      19. return render_template('login.html')
      20. @app.route('/testurlfor')
      21. def redirectaliastest():
      22. print(session) # login中设置的session在这里能打印出
      23. return render_template('flaskindex.html')
      24. if __name__ == "__main__":
      25. app.run()

      关于Flask的中间件调用机制:

      所有的WSGI在执行时,即实例化时,要先执行__call__()方法,

      def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
      
          return self.wsgi_app(environ, start_response)

      这个方法返回的是是执行wsgi_app方法的结果,然后在进入到Flask。

      我们可以将这个wsgi_app换成我们自定义的类,在__call__方法中添加我们自己的代码,最后在调用原来的wsgi_app,这样就在请求处理前,先经过了我们自己的处理,像Django的中间件就是这种机制实现的。

      1. from flask import Flask,render_template,make_response,session,request,redirect,url_for
      2. app = Flask(__name__)
      3. app.config.update(SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/')
      4. def myfun():
      5. @app.route('/index/')
      6. def index():
      7. # return "hello world!"
      8. # return render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17})
      9. obj = make_response(render_template('flaskindex.html',k0=myfun,k1='hello',k2=['a','b','c'],k3={'name':'haha1','age':17}))
      10. obj.set_cookie('usern','xiaohua')
      11. return obj
      12. @app.route('/login/',methods=['GET','POST'])
      13. def login():
      14. if request.method =='POST':
      15. session['user'] = request.form.get('user')
      16. url = url_for('redirectaliastest')
      17. return redirect(url)
      18. else:
      19. return render_template('login.html')
      20. @app.route('/testurlfor')
      21. def redirectaliastest():
      22. print(session)
      23. return render_template('flaskindex.html')
      24. class Foo:
      25. def __init__(self,w):
      26. self.w = w
      27. def __call__(self, environ,start_response):
      28. print("自己的中间件")
      29. obj = self.w(environ,start_response)
      30. return obj
      31. if __name__ == "__main__":
      32. app.wsgi_app = Foo(app.wsgi_app)
      33. # 将原来的wsgi_app换成我们的类,Foo加上括号,即Foo()会先init,然后call
      34. # call的时候先执行我们的逻辑(相当于中间件),最后执行原来的wsgi_app
      35. # 这种方法有点装饰器的设计模式
      36. app.run()

      启动后,页面请求过程:

      Flask的消息:取一次就消失:

      放置在session中,使用flash(value),取用,get_flashed_message(),取完就删除了。

  • 相关阅读:
    Java 在PDF中替换文字(详解)
    resvr.exe 电脑病毒清理
    记录YDLidar驱动包交叉编译时出现的一点问题
    java中函数
    【生成对抗网络学习 其一】经典GAN与其存在的问题和相关改进
    C高级day1
    ArcGIS Pro设置谷歌影像(无水印)
    搭建vue3.2+vite+ts+pinia项目
    力扣(LeetCode)181. 超过经理收入的员工(2022.06.29)
    Docker--harbor私有仓库部署与管理
  • 原文地址:https://blog.csdn.net/kaoa000/article/details/132686075