框架 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

原文地址:https://www.cnblogs.com/olivia2018/p/9174718.html