Flask

一、Flask

安装:pip3 install flask

flask:短小精悍,可扩展的一个web框架(上下文管理机制)

依赖:wsgi:werkzurg

学习werkzurg:

示例一:
    from werkzeug.wrappers import Request, Response
    from werkzeug.serving import run_simple

    def run(environ,start_response):

          return [b"asdfasdf"]

    if __name__ == '__main__':

          run_simple('localhost', 4000, run)
                    
示例二:
   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)
        

对django和flask的认识?

django:是一个大二全的一个框架,里面有很多的组件供开发者使用,让开发者可以很快的快速开发。

flask:是一个很小的web框架,可以写一个小的项目。没有组件供开发者使用,它可以通过第三方组件。

django和flask最大的不同点:django的request是通过传参的方式获得,flask是通过导入request获得。

flask知识点:

给你一个路径 “settings.Foo”,可以找到类并获取去其中的大写的静态字段。

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))

1.配置文件:

所有配置都在app.config中
app.config["xx"] = 123
app.config.from_object("类的路径")
应用:importlib、getattr
django中间件
rest framework全局配置

app.config.from_object("settings.DevelopmentConfig")
        
        
        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

2.路由系统

endpoint,反向生成URL,默认函数名
- url_for('endpoint') / url_for("index",nid=777)
- 动态路由:
      @app.route('/index/<int:nid>',methods=['GET','POST'])
    def index(nid):
        print(nid)
        return "Index"            

3.FBV

4.请求相关

# 请求相关信息
# 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))


- 请求 
request.form 
request.args
request.method 
- 响应         
render
redirect
- session 
session['xx'] = 123
session.get('xx')

5.响应

响应体:
return “asdf”
return jsonify({'k1':'v1'})
return render_template('xxx.html')
return redirect()
            
定制响应头:   
obj = make_response("asdf")
obj.headers['xxxxxxx'] = '123'
obj.set_cookie('key', 'value')
return obj

示例程序:学生管理

版本一:
@app.route('/index')
def index():
if not session.get('user'):
    return redirect(url_for('login'))
    returnrender_template('index.html',stu_dic=STUDENT_DICT)
版本二:
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')

6.模板渲染

基本数据类型:可以执行python语法,如:dict.get()  list['xxx']

传入函数

  --django,自动执行

 --flask,不自动执行

(1)全局定义函数

@app.template_global()
def sb(a1, a2):
# {{sb(1,9)}}
    return a1 + a2

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

(2)模板继承

layout.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>模板</h1>
{% block content %}{% endblock %}
</body>
</html>
            
tpl.html
{% extends "layout.html"%}


{% block content %}
{{users.0}}
                    

{% endblock %}    
- include 
    
    
{% include "form.html" %}
            
            
form.html 
<form>
asdfasdf
asdfasdf
                    
</form>
- 宏
{% macro ccccc(name, type='text', value='') %}
<h1>宏</h1>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
<input type="submit" value="提交">
{% endmacro %}

{{ ccccc('n1') }}

{{ ccccc('n2') }}

(3)安全

         前端:{{u|safe}}

    后端:MarkUp('asdef')

7.session

加密后放置在用户浏览器的cookie中。
流程:
请求到来
视图函数
请求结束
配置文件

当请求刚到来:flask读取cookie中session对应的值:adw,将该值解密并反序列化成字典,放入内存以便视图函数使用。

视图函数:

@app.route('/ses')
def ses():
    session['k1'] = 123
    session['k2'] = 456
del session['k1']

    return "Session"
        
    session['xxx'] = 123
    session['xxx']

当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中

8.闪现,在session中存储一个数据,读取时通过pop将数据移除

from flask import Flask,flash,get_flashed_messages
@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"

9.中间件

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()

10.特殊装饰器

1. before_request
        
2. after_request
        
示例:
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()
        
3. before_first_request
        
from flask import Flask
app = Flask(__name__)

@app.before_first_request
def x1():
        print('123123')


@app.route('/index')
def index():
    print('index')
    return "Index"


@app.route('/order')
def order():
    print('order')
    return "order"


if __name__ == '__main__':

        app.run()

        
4. template_global
        
5. template_filter
        
6. errorhandler
@app.errorhandler(404)
def not_found(arg):
    print(arg)
    return "没找到"            

 Flask源码入口:

from werkzeug.wrappers import Response
from werkzeug.serving import run_simple

class Flask(object):
def __call__(self,environ, start_response):
    response = Response('hello')
    return response(environ, start_response)

def run(self):
    run_simple('127.0.0.1', 8000, self)



app = Flask()

if __name__ == '__main__':
    app.run()

二、Flask进阶版

1.路由+视图

a、路由设置的两种方式

@app.route('/xxx')
def index():
    return "index"

            
def index():
    return "index"
app.add_url_rule("/xxx",None,index)

注意事项:1.不用让endpoint重名  2.如果重名函数也要一定要相同

b、参数

rule,                       URL规则
view_func,                  视图函数名称
endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
methods=None,               允许的请求方式,如:["GET","POST"]
strict_slashes=None,        对URL最后的 / 符号是否严格要求,
redirect_to=None,           重定向到指定地址

defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
subdomain=None,             子域名访问

c、CBV

import functools
from flask import Flask,views
app = Flask(__name__)


def wrapper(func):
@functools.wraps(func)
def inner(*args,**kwargs):
    return func(*args,**kwargs)

    return inner



class UserView(views.MethodView):
    methods = ['GET']
    decorators = [wrapper,]

    def get(self,*args,**kwargs):
        return 'GET'

    def post(self,*args,**kwargs):
        return 'POST'

            app.add_url_rule('/user',None,UserView.as_view('uuuu'))

if __name__ == '__main__':
    app.run()

d、自定义正则

from flask import Flask,url_for

app = Flask(__name__)

# 步骤一:定制类
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""

def __init__(self, map, regex):
    super(RegexConverter, self).__init__(map)
    self.regex = regex

def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
:param value:
:return:
"""
    return int(value)

def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
:param value:
:return:
"""
val = super(RegexConverter, self).to_url(value)
        return val

# 步骤二:添加到转换器
app.url_map.converters['reg'] = RegexConverter

"""
1. 用户发送请求
2. flask内部进行正则匹配
3. 调用to_python(正则匹配的结果)方法
4. to_python方法的返回值会交给视图函数的参数

"""
# 步骤三:使用自定义正则
@app.route('/index/<reg("d+"):nid>')
def index(nid):
    print(nid,type(nid))

    print(url_for('index',nid=987))
    return "index"

if __name__ == '__main__':
    app.run()

2.session实现原理(源码)

3.蓝图

目标:给开发者提供目录结构

其他:

  自定义模板、静态文件

  某一类url添加前缀

  给一类url添加before_request

4.threading.local(和flask无任何关系)

作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)

import threading
from threading import local
import time

obj = local()


def task(i):
    obj.xxxxx = i
    time.sleep(2)
        print(obj.xxxxx,i)

for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()    

问题:如何获取一个线程的唯一标记?threading.get_ident()

   根据字典自定义一个类似于threading.local功能?

import time
import threading

DIC = {}

def task(i):
    ident = threading.get_ident()
    if ident in DIC:
        DIC[ident]['xxxxx'] = i
    else:
        IC[ident] = {'xxxxx':i }
    time.sleep(2)

        print(DIC[ident]['xxxxx'],i)

for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()

根据字典自定义一个为每个协程开辟空间进行存储数据

import time
import threading
import greenlet

DIC = {}

def task(i):
                    
    # ident = threading.get_ident()
    ident = greenlet.getcurrent()
    if ident in DIC:
        DIC[ident]['xxxxx'] = i
    else:
        DIC[ident] = {'xxxxx':i }
    time.sleep(2)

        print(DIC[ident]['xxxxx'],i)

    for i in range(10):
        t = threading.Thread(target=task,args=(i,))
        t.start()

通过getattr/setattr 构造出来 threading.local的加强版(协程)

import time
import threading
try:
        import greenlet
    get_ident =  greenlet.getcurrent
except Exception as e:
    get_ident = threading.get_ident

class Local(object):
        DIC = {}

    def __getattr__(self, item):
        ident = get_ident()
        if ident in self.DIC:
            return self.DIC[ident].get(item)
        return None

    def __setattr__(self, key, value):
        ident = get_ident()
        if ident in self.DIC:
            self.DIC[ident][key] = value
        else:
            self.DIC[ident] = {key:value}
                        

obj = Local()

def task(i):
    obj.xxxxx = i
    time.sleep(2)
    print(obj.xxxxx,i)

for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()        

5.上下文管理(第一次)

请求到来时候:

  ctx = RequestContext(self, environ) # self是app对象,environ请求相关的原始数据
  ctx.request = Request(environ)
  ctx.session = None

  将包含了request/session的ctx对象放到“空调”
    {
      1232:{ctx:ctx对象}
      1231:{ctx:ctx对象}
      1211:{ctx:ctx对象}
      1111:{ctx:ctx对象}
      1261:{ctx:ctx对象}
    }

视图函数:

    from flask import request,session

    request.method

请求结束:

    根据当前线程的唯一标记,将“空调”上的数据移除。

原文地址:https://www.cnblogs.com/xu1686318405/p/9178699.html