• 框架 Flask


    Flask  基于 Python开发 ,依赖 jinjia2模板 和 Werkzeug WSGI服务 的一个微型框架。

      Werkzeug本质是Socket服务端,用于 接收http请求 并对请求进行预处理,然后触发Flask框架。

      开发人员 基于 Flask框架提供的功能 对请求进行相应处理,并返回给用户。

      Flask的特点是“微小”(micro),保持核心简单而易于扩展。Flask 支持用扩展来给应用添加功能。如:数据库集成,表单验证,用户认证等。

    # 安装
    pip3 install flask
    from werkzeug.wrappers import Request, Response
    
    @Request.application
    def hello(request):
        return Response('Hello World!')
    
    if __name__ == '__main__':
        from werkzeug.serving import run_simple
        run_simple('localhost', 4000, hello)
    werkzeug

    基本使用

     from flask import Flask
     app = Flask(__name__)
      
     @app.route('/')
     def hello_world():
         return 'Hello World!'
      
     if __name__ == '__main__':
         app.run()

    Flask 提供的功能

    一、配置文件

    flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:

    {
            'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
            'TESTING':                              False,                          是否开启测试模式
            'PROPAGATE_EXCEPTIONS':                 None,                          
            'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
            'SECRET_KEY':                           None,
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
            'USE_X_SENDFILE':                       False,
            'LOGGER_NAME':                          None,
            'LOGGER_HANDLER_POLICY':               'always',
            'SERVER_NAME':                          None,
            'APPLICATION_ROOT':                     None,
            'SESSION_COOKIE_NAME':                  'session',
            'SESSION_COOKIE_DOMAIN':                None,
            'SESSION_COOKIE_PATH':                  None,
            'SESSION_COOKIE_HTTPONLY':              True,
            'SESSION_COOKIE_SECURE':                False,
            'SESSION_REFRESH_EACH_REQUEST':         True,
            'MAX_CONTENT_LENGTH':                   None,
            'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
            'TRAP_BAD_REQUEST_ERRORS':              False,
            'TRAP_HTTP_EXCEPTIONS':                 False,
            'EXPLAIN_TEMPLATE_LOADING':             False,
            'PREFERRED_URL_SCHEME':                 'http',
            'JSON_AS_ASCII':                        True,
            'JSON_SORT_KEYS':                       True,
            'JSONIFY_PRETTYPRINT_REGULAR':          True,
            'JSONIFY_MIMETYPE':                     'application/json',
            'TEMPLATES_AUTO_RELOAD':                None,
        }  

     配置方法

    方式一:
        app.config['DEBUG'] = True
     
        PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
    
    方式二:
    # app.config.from_object("python类或类的路径")  PS: 从sys.path中已经存在路径开始写 
    app.config.from_object("settings.DevelopmentConfig")
    
    settings.py
    class Config(object):
    	DEBUG = False
    	TESTING = False
    	DATABASE_URI = 'sqlite://:memory:'
    
    
    class ProductionConfig(Config):
    	DATABASE_URI = 'mysql://user@localhost/foo'
    
    
    class DevelopmentConfig(Config):
    	DEBUG = True
    
    
    class TestingConfig(Config):
    	TESTING = True
    
    PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
            
                settings.py
                    class Foo:
                        DEBUG = True
                        TEST = True
                    
                xx.py 
                    import importlib
    
                    path = "settings.Foo"
    
                    p,c = path.rsplit('.',maxsplit=1)
                    m = importlib.import_module(p)
                    cls = getattr(m,c)
    
                    # 如果找到这个类?
                    for key in dir(cls):
                        if key.isupper():
                            print(key,getattr(cls,key))
    # 获取路径,根据字符串导入模块,反射得到类,
       获取类中大写的变量和值。
    app.config.from_object源码分析

    二、路由

    - <nid> 默认为字符串,还有int,path,any,float,uuid。
    - methods默认只有GET
    - endpoint 用来反向生成URL,如果没有设置,则默认函数名
    - url_for('endpoint') / url_for("index",nid=777)  # /index/77 
    - 动态路由:
    	@app.route('/index/<int:nid>',methods=['GET','POST'],endpoint='n1')
    	def index(nid):
    		print(nid)
                    print(url_for('n1'))
    		return "Index"            

    三、视图

    四、请求相关

    django中的request是参数,而flask中的request是导入的。

     from flask import request
    # 请求相关信息
    	# request.method 请求方法
    	# request.args 
    	# request.form    表单提交数据
    	# request.values
    	# 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
    	# request.files
    	# obj = request.files['the_file_name']
    	# obj.save('/var/www/uploads/' + secure_filename(f.filename))

    五、响应

    from flask importrender_template,redirect,jsonify,make_response 
     
    响应体: 
      return “字符串” 
      return jsonify({'k1':'v1'}) 
      return render_template('xxx.html',**{}) 
      return redirect() 
    
    定制响应头: 
      obj = make_response("asdf") # obj是flask.wrappers.Response类型
      obj.headers['xxxxxxx'] = '123' 
      obj.set_cookie('key', 'value') 
      obj.delete_cookie('key')
      return obj
    View Code

    六、session

    session需要从flask导入,使用时加密后存储在用户浏览器的cookies。

    使用session,要设置 app.secret_key.

    from Flask import session
    设置:session['username'] = 'xxx' 删除:session.pop('username', None) del session['username'] 当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。 视图函数: @app.route('/ses') def ses(): session['k1'] = 123 session['k2'] = 456 del session['k1'] return "Session" 当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。

    练习:利用上面的flask知识做一个简单的用户认证功能。

    	示例程序:学生管理
    		
    		版本一:
    			@app.route('/index')
    			def index():
    				if not session.get('user'):
    					return redirect(url_for('login'))
    				return render_template('index.html',stu_dic=STUDENT_DICT)
    		版本二: 在需要认证功能的视图前添加@auth
    			import functools
    			def auth(func):
    				@functools.wraps(func)
    				def inner(*args,**kwargs):
    					if not session.get('user'):
    						return redirect(url_for('login'))
    					ret = func(*args,**kwargs)
    					return ret
    				return inner
    		
    			@app.route('/index')
    			@auth
    			def index():
    				return render_template('index.html',stu_dic=STUDENT_DICT)
    		
    			应用场景:比较少的函数中需要额外添加功能。
    			
    		版本三:before_request  只有写一次就在每一个视图前添加认证功能
    			@app.before_request
    			def xxxxxx():
    				if request.path == '/login':
    					return None
    
    				if session.get('user'):
    					return None
    
    				return redirect('/login')

    七、模板渲染(jinjia2)

    Flask使用的是Jinja2模板,所以其语法和Django几乎无差别。

    区别一:传入函数时,django自动执行,flask要加()才执行。

    1 u = "<input type='text' />"
    2 
    3 前端:{{ u|safe }}
    4 
    5 后端:from Flask import  MarkUp
    6 
    7      MarkUp(u)         # 和django的mark_safe 等价        
    1 想要html标签安全显示,不被转译成字符串显示
     1 {% macro c1(name,type="text",value=' ') %}
     2 
     3   <h1>宏</h1>
     4   <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
     5   <input type="submit" value="提交">
     6 
     7 {% endmacro %}
     8 
     9 {{% c1(" n1") %}}
    10 
    11 {{% c2 (" n2") %}}
    2 宏 django没有。调用宏时,才生成 html标签
     1 base.html
     2     <!DOCTYPE html>
     3     <html lang="zh-CN">
     4     <head>
     5         <meta charset="UTF-8">
     6         <title>Title</title>
     7         <meta name="viewport" content="width=device-width, initial-scale=1">
     8     </head>
     9     <body>
    10         <h1>模板</h1>
    11 
    12         {% block content %}{% endblock %}
    13 
    14     </body>
    15     </html>
    16 
    17 tpl.html
    18     {% extends "base.html"%}
    19 
    20 
    21     {% block content %}
    22         {{users.0}}
    23         
    24 
    25     {% endblock %}
    3 模板继承
    1 xxx.html
    2 {% include "form.html" %}
    3 
    4 form.html
    5 <form>
    6     <input type="text">
    7 </form>
    4 include
     1 后端:
     2 @app.template_global()
     3 def sb(a1, a2):
     4     return a1 + a2
     5 
     6 @app.template_filter()
     7 def db(a1, a2, a3):
     8     
     9     return a1 + a2 + a3    
    10 
    11 前端:
    12 {{sb(1,9)}}
    13 
    14 {{ 1|db(2,3) }}
    5 全局定义函数 在前端调用

    区别二 :flask可以 {% if 1|db(2,3) %}可以做判断 在模板里做计算
    区别三:django没有宏

    区别四:可以执行python语法,如:dict.get()  list['xx']

    区别五:后端: MarkUp("asdf") 

     1             {% for k,v in  stu_dic.items() %}
     2             # 像python语法一样,要加()遍历k或v
     3             # for k in stu_dic / for k in stu_dic.keys()/ for k in stu.values() 
     4                 <tr>
     5                     <td>{{k}}</td>
     6                     <td>{{v.name }}</td>
     7                     <td>{{v[age]}}</td>
     8                     <td>{{v.gender}}</td>
     9                     <td>
    10                         <a href="/detail/{{k}}">查看详细</a>
    11                         |
    12                         <a href="/delete/{{k}}">删除</a>
    13 
    14                     </td>
    15                 </tr>
    16             {% endfor %}
    17 
    18 stu_dic={
    19      1 :{name:"alex",age:"18",gender:""},
    20      。。。。。。
    21      }                    
    渲染语法

    八、闪现flash

    在session中存储一个数据,读取时通过pop将数据移除。

    from flask import Flask,flash,get_flashed_messages
        # print(session['uuuuu'])
        # del session['uuuuu']
        # session.pop('uuuuu')
    @app.route('/page1')
    def page1():
    
        flash('临时数据存储','error')
        flash('sdfsdf234234','error')
        flash('adasdfasdf','info')
    
        return "Session"
    
    @app.route('/page2')
    def page2():
        print(get_flashed_messages(category_filter=['error']))
        return "Session"
    
    {{% for message in get_flashed_messages() %}}
    flash的使用及原理

    九、中间件

    原理:类中的__call__方法 ,用户发起请求时,才执行。对象() 时调用call(回调函数)。

    中间件的实现:在执行call方法之前,做一个操作,call方法执行之后做一个操作。

    	class Middleware(object):
    				def __init__(self,old):
    					self.old = old
    
    				def __call__(self, *args, **kwargs):
    					ret = self.old(*args, **kwargs)
    					return ret
    
    
    			if __name__ == '__main__':
    				app.wsgi_app = Middleware(app.wsgi_app)
    				app.run()
    			

    十、特殊装饰器

    1 @app.before_request  正序 返回None或不返回,继续向下执行,否则请求结束。

    2 @app.after_request     倒序,参数:response,有返回值。

                    from flask import Flask
                    app = Flask(__name__)
    
    
                    @app.before_request
                    def x1():
                        print('before:x1')
                        return ''
    
                    @app.before_request
                    def xx1():
                        print('before:xx1')
    
    
                    @app.after_request
                    def x2(response):
                        print('after:x2')
                        return response
    
                    @app.after_request
                    def xx2(response):
                        print('after:xx2')
                        return response
    
    
    
                    @app.route('/index')
                    def index():
                        print('index')
                        return "Index"
    
    
                    @app.route('/order')
                    def order():
                        print('order')
                        return "order"
    
    
                    if __name__ == '__main__':
    
                        app.run()       
    结果: x1 xx1 xx2 x2                     
    示例

    3. @app.before_first_request 只在第一次请求前

    4. @app.template_global

    @app.template_global()
    def sb(a1, a2):
            # 在前端渲染 {{sb(1,9)}}
          return a1 + a2
    View Code

    5. @app.template_filter

    @app.template_filter()
    def db(a1, a2, a3):
         # 前端渲染 {{ 1|db(2,3) }}
    return a1 + a2 + a3

    6. @app.errorhandler(404) # 编辑错误页面 500、403、404....

    @app.errorhandler(404)
    def not_found(arg):
        print(arg)
        return "没找到"
    View Code

    十一、蓝图

    使用:看笔记

    目标:给开发者提供目录结构
    其他作用: - 自定义模板、静态文件的设置
          -给 某一类url添加前缀
            - 给某一类url添加before_request

  • 相关阅读:
    如何在ASP.NET Core中使用JSON Patch
    IDEA中Maven依赖更新问题 国
    vue实现文字上下滚动效果
    mac 安装 homebrew 超快镜像
    linux查找文件命令有哪些
    Git 操作的 token 验证
    mysql重置主键
    PHP获取特定字符串中间的内容
    MySQL 连接出现 Authentication plugin ‘caching_sha2_password‘ cannot be loaded
    oracle mysql sqlserver三种数据库的查看索引和新增普通索引sql语句
  • 原文地址:https://www.cnblogs.com/olivia2018/p/9174718.html
Copyright © 2020-2023  润新知