最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 一文让你深入了解Flask框架

    正文概述    2020-06-17   522

    一文让你深入了解Flask框架

    一、初识Flask

    Flask扩展应用扩展包

    二、认识werkzurg,Flask最重要的依赖

    Python Web 框架工具包 werkzeug

    # 引用werkzurg的功能模块
    from werkzeug.wrappers import Request,Response
    from werkzeug.serving import run_simple
    # 底层的用法
    def run(environ,start_response):
        return [b'abcdefg'] 
    if __name__ == '__main__':
        run_simple('localhost',4000,run) # 监听端口并执行run函数
        # 另一种用法
    @Response.application
    def hello(request):
        return Response('Hello World!')
        '''
            return到底返回到客户端什么内容?
            1、状态码:status code 200,301,404,返回一个响应的客户端的状态码;
            2、content-type:告诉客户端用什么方式解析返回的值;
            3、其他的返回头信息。
        '''
    if __name__ == __main__:
        run_simple('localhost',4000,hello)

    三、Flask 使用

    3.1、简单的登录

    from flask import Flask as fk , request,render_template as render,redirect,session,make_response
    app = fk(__name__)
    app.secret_key = 'abckd' # 设置session 的加密值
    @app.route('/',methods=['GET','POST'])
    def index():
        if request.method == 'POST':
            user = request.form.get('user')
            pwd = request.form['pwd']
            if user == 'admin' and pwd == '123':
                print(user,pwd)
                return '登录成功!'
        return render('index.html',h1='你好')
        # home.add_url_rule('/',view_func=index) #第二种路由的声明方式,必须已“/”开头
    if __name__ == '__main__':
        app.run(debug=True,host='192.168.0.11',port=5000) 
    '''
    执行werkzurg中的run_simple('localhost',4000,hello)
    这里只是socket进行了请求监听,当浏览器发起请求后,执行内部的__call__()方法。
    '''

    3.2、静态文件的处理方法

    <!-- 使用静态文件需要删除 <!DOCTYPE html> -->
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/index.css" type="text/css">
        <!-- javascript引用时必须添加type="text/javascript" -->
        <script language="javaacript" src="/statics/jquery.min.js" type="text/javascript"></script> 
        <!-- 推荐使用这样加载静态文件 -->
        <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css"> 
        <!-- url_for(),函数配置静态文件,一定要在Flask类中设置静态文件的路径和别名,蓝图中设置静态文件路径和别名是
        不能使用的 -->
    </head>
    <body>
    <h1>index</h1>
    <h1>{{ h1 }}</h1>
    <form action="/" method="POST">
        <input type="text" name="user" >
        <input type="password" name="pwd">
        <input type="submit" value="提交">
    </form>
    </body>

    使用 url_for 函数获取静态资源时,必须在实例化 Flask 对象的时候设置 static_url_path(别名),static_folder(静态文件路径)。

    from flask import Flask
    from .views.index import home
    def shb():
        app = Flask(__name__,static_url_path='/static',static_folder='./public',template_folder='./template')
        '''
        PS:
         1、static_folder的路径一定要设置正确。
         2、static_url_path的值必须是’/static‘,其他测试无效。
         3、url(’static‘,filename='静态文件路径') 第一个值必须是’static‘,其他测试无效。
         4、template_folder 配置注意存放路径。
         5、蓝图中就不再配置存放静态文件的路径和引用别名了;模板也不用再配置,这里是全局配置。
        '''
        app.register_blueprint(home,url_prefix="/api")
        return app

    3.3、Flask 简单运用

    from flask import Flask,render_template,request,redirect,session
    app = Flask(__name__) # __name__ 可以修改为任意字符串,并可以传入多个参数
    app.secret_key = 'abckd' # 设置session加密多余字符串
    # 路由装饰器,必须已“/”开头
    @app.route('/login',methods=['GET','POST'])
    # 定义与路由装饰器匹配的执行函数
    def login():
        print(request.method) # request 需要导入,获取请求的信息
        session['key] = value # 设置session值
        session.get('key') # 获取session的值
        return render_template('login.html',**{key:value})
        #return render_template('login.html',key=value)
    if __name__ == '__main__':
        app.run(url,prot)

    3.4、Flask 的实现基础

    Python Threading 线程模块用法

    3.4.1、Threading.local 多线程

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

    import threading
    from threading import local
    local_obj = local() # 实例化local对象
    def task(i):
        local_obj.xxx = i # 为local对象设置一个参数
        print(local_obj.xxx,i) # 获取local对象中的参数
        # threading.get_ident() 获取线程的唯一标示
        print(threading.get_ident(),i)
    for i in range(10):
        t = threading.Thread(target=task,args(i,)) # 创建线程
        t.start() # 开始执行线程

    3.4.2、根据字典自定义类似Threading.localz

    import threading
    import greenlet # 获取协程信息
    DIC = {}
    def task(i):
    # 获取协成的唯一标记
    # indent = greenlet.getcurrent()
    # treading.get_ident() 获取线程的唯一标记
        indent = treading.get_ident()
        if indent in DIC:
            DIC[indent]['xxx'] = i
        else:
            DIC[indent] = {'xxx':i}
        print(DIC[index][xxx],i) # 打印字典中的参数
    for i in range(10):
        t = threading.Thread(target=task,args=(i,)) # 创建线程
        t.start() # 开始执行线程

    3.4.3、自定义升级版Threading.localz

    此版本中协程与线程可以完全的兼容,完成对请求的数据隔离。
    为什么需要给线程和协程数据进行隔离?
    在多个请求的时候,由于每个请求的信息不相同,所以需要对不同的请求信息进行分类管理(数据隔离),从而防止数据混乱;
    这样在需要使用视图函数取得用户请求信息的时候,才能根据不同的信息进行取值和修改。
    import threading
    import time
     
    try:
        import greenlet # 获取协程信息
        get_indent = greenlet.getcurrent
    except Exception as e:
        get_indent = threading.get_ident
    class local(object):
    # DIC={}
        def __init__(self):
       # pass
            object.__setattr__(self,'DIC',{}) # 通过父类的方法设置类属性
        def __getattr__(self,item):
            indent = get_indent()
            if indent in self.DIC:
                return self.DIC[indent].get(item)
            else:
                return None
        
        def __setattr__(self,key,value):
            indent = get_indent()
            if indent in self.DIC:
                self.DIC[indent][key] = value
            else:
                self.DIC[indent]= {key:value}
        
        obj = local() # 类在实例化的时候运行__init__()方法
      '''
        obj.xx # 对象.方法的时候运行__getattr__()方法,并且把xx当参数传入
        obj.xx = 123 # 对象.方法赋值的时候运行__setattr__()方法,并且把xx和123当参数传入
      '''
        def task(i):
            obj.xxx = i
            time.sleep(2)
            print(obj.xxx,i)
        for i in range(10):
            t = threading.Thread(target=task,args=(i,)) # 创建线程
            t.start() # 开始执行线程

    3.4.4、Flask简单执行流程

    3.4.4.1、Flask 的基本执行流程

    封装 requestContext 对象, full_dispatch_request(视图函数 执行), response返回
    从app.run() 开始 -->>
    Flask的__call__方法-->>
    wsgi_app (封装RequestContext(request,session)对象到 localstack) -->>
    full_dispatch_request(视图函数 执行) -->>
    执行扩展(before_request) ,触发信号 -->>
    获取response -->>
    pop reqeust、session -- >>
    结束

    3.4.4.2、Flask 源码执行顺序

    (1)threading local 和 flask的自定义local对象 
            - 基于本地线程 可以实现线程隔离。
    (2)请求到来
            封装  ctx = RequestContext(request,session)
                 ctx -- 放入 Local __storage__ { 'id':{stack:[ctx]} }
    (3)执行视图
            导入 request
            print(reqeust) -- >> localproxy __str__
            reqeust.method -- >> localproxy __getattr__
            reqeust + 1 -- >> localproxy __add__    
            调用_lookup_req_object函数,去local中的ctx中获取reqeust session
    (4)请求结束
            ctx.auto_pop
            ctx 从 local 中移除

    一文让你深入了解Flask框架

    四、Flask中的方法

    Flask request 属性详解

    # Flask 中的模块
    from flask import Flask,render_template,request,redirect,session
    request.method # 获取请求的方法
    request.args # 获取get请求的数据
    request.args.get('') # 获取get请求指定的值
    request.form # 获取post请求的数据
    request.form.get('') # 获取post请求指定的值
    files = request.files.get('') # 获取POST上传的文件信息
    files.filename # 获取上传的文件名
    files.stream # 获取上传文件的内容
    files.save('文件路径','上传文件的内容',) # 保存上传文件到本地
    '''
    session 的处理 flask 放入的是加密cookie中的,继承了字典的所有功能;
    flask读取cookie中session对应的值,将该值解密并反序列化成为字典,供视图函数使用;
    当请求结束时,flask会读取内存中字典的值,进行序列化并加密,写入到浏览器cookie中。
    '''
    session['key'] = value # 为session赋值 保存在浏览器的cookie中
    session.get('') # 获取session的值
    del session['key'] # 删除
    # 设置响应头
    rst = make_response('aaa') # 设置返回加密
    rst.headers['Access-Control-Allow-Origin'] = '*' # 允许请求的域名
    rst.headers['Access-Control-Allow-Methods'] = 'POST' # 允许POST请求
    # Flask() 配置项 
    import_name, # 文件名称
    static_url_path=None, # 静态文件别名
    static_folder='static', # 静态文件路径
    static_host=None,
    host_matching=False,
    subdomain_matching=False,
    template_folder='templates', # 模板文件路径
    instance_path=None, # 实例文件路径
    instance_relative_config=False, # 实例配置文件相对路径
    root_path=None # 根文件路径
    # Flask 配置文件 app.config['ENV'] 获取内部的值
    'ENV':                        None,
    'DEBUG':                       None,
    'TESTING':                     False,
    'PROPAGATE_EXCEPTIONS':             None,
    'PRESERVE_CONTEXT_ON_EXCEPTION':       None,
    'SECRET_KEY':                   None,
    'PERMANENT_SESSION_LIFETIME':         timedelta(days=31), # session保留时间
    'USE_X_SENDFILE':                 False,
    'SERVER_NAME':                   None, # 设置域名 xxx.com
    'APPLICATION_ROOT':               '/',
    'SESSION_COOKIE_NAME':             'session',
    'SESSION_COOKIE_DOMAIN':            None,
    'SESSION_COOKIE_PATH':             None,
    'SESSION_COOKIE_HTTPONLY':           True,
    'SESSION_COOKIE_SECURE':            False,
    'SESSION_COOKIE_SAMESITE':           None,
    'SESSION_REFRESH_EACH_REQUEST':       True, # session以什么方式保存保留时间
    'MAX_CONTENT_LENGTH':              None, # 上传文件大小限制
    'SEND_FILE_MAX_AGE_DEFAULT':         timedelta(hours=12),
    'TRAP_BAD_REQUEST_ERRORS':           None,
    'TRAP_HTTP_EXCEPTIONS':             False,
    'EXPLAIN_TEMPLATE_LOADING':          False,
    'PREFERRED_URL_SCHEME':             'http',
    'JSON_AS_ASCII':                 True,
    'JSON_SORT_KEYS':                 True,
    'JSONIFY_PRETTYPRINT_REGULAR':        False,
    'JSONIFY_MIMETYPE':               'application/json',
    'TEMPLATES_AUTO_RELOAD':            None,
    'MAX_COOKIE_SIZE': 4093,
    'SQLALCHEMY_DATABASE_URI' :                'mysql://root:root@127.0.0.1/mysql', # 配置数据库连接
    'SQLALCHEMY_TRACK_MODIFICATIONS' :         False,
    # 自定义配置
    'SERVER_PORT':                             8000, # 端口
    'IP_PATH':                                 '127.0.0.1',# 访问链接
    # 绑定二级域名的方法
    app.url_map.default_subdomain = 'www' # 设置域名前缀
    app.config['SERVER_NAME'] = 'testing.com' # 设置域名
    app.register_blueprint(public, subdomain='static') # 设置静态文件
    PS:要指定默认的域名(app.url_map.default_subdomain ),不然无法访问;
        SERVER_NAME、app.url_map.default_subdomain 在开发环境是不能加,会报404。

    五、Flask配置文件

    5.1、通过字符串获取 Class 并运行(反射)

    hasattr、setattr、getattr 解释

    hasattr(object, name) 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。

    class test():
        name="xiaohua"
        def run(self):
            return "HelloWord"
    t=test()
    hasattr(t, "name") #判断对象有name属性
    #输出:True
    hasattr(t, "run")  #判断对象有run方法
    #输出:True

    setattr(object, name, values) 给对象的属性赋值,若属性不存在,先创建再赋值。

    getattr(object, name[,default]) 可以取出来某个属性,这个属性如果是一个字段,就得到字段的值了,如果是一个方法,就得到这个方法的指针了,然后可以根据方法的指针来调用方法。

    class test():
        name="xiaohua"
        def run(self):
            return "HelloWord"
    t=test()
    setattr(t,'max',30) #在对象中设置max属性
    getattr(t, "name") #获取name属性,存在就打印出来。
    #输出:'xiaohua'
    getattr(t, "run")  #获取run方法,存在就打印出方法的内存地址。
    #输出:<bound method test.run of <__main__.test instance at 0x0269C878>>
    getattr(t, "run")()  #获取run方法,后面加括号可以将这个方法运行。
    #输出:'HelloWord'
    getattr(t, "age")  #获取一个不存在的属性。
    '''
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: test instance has no attribute 'age'
    '''
    getattr(t, "age","18")  #若属性不存在,返回一个默认值。
    #输出:'18'

    5.2、Flask配置文件的原理

    # settings.py 文件
    class Foo(object):
        DEBUG = True
    # 获取settings.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))
    # 输出
    # DEBUG True

    5.3、Flask 三种加载配置方式

    在 Flask 程序运行的时候,可以给 Flask 设置相关配置,比如:配置 Debug 模式,配置数据库连接地址等等,设置 Flask 配置有以下三种方式:

    从配置对象中加载(常用):app.config.from_object()

    从配置文件中加载:app.config.from_pyfile()

    从环境变量中加载(了解):app.config.from_envvar()

    以下演练以设置应用程序的 DEBUG(调试模式) 为例,设置应用为调式模式这后,可以实现以下功能。

    5.3.1、配置文件

    创建配置文件 config.py,在配置文件中添加配置。

    app.config.from_pyfile('config.py')

    5.3.2、环境变量(了解)

    加载指定环境变量名称所对应的相关配置

    app.config.from_envvar('FLASKCONFIG')
    # 读取配置
    app.config.get()

    在视图函数中使用 current_app.config.get() 注:Flask 应用程序将一些常用的配置设置成了应用程序对象的属性,也可以通过属性直接设置/获取某些配置:app.debug = True

    5.3.3、Flask配置文件的原理

    # settings.py 文件
    class Foo(object):
        DEBUG = True
    # 获取settings.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))
    # 输出
    # DEBUG True

    5.4、配置对象加载配置

    '''
     app.config # 获取配置文件对象
     app.config['ENV'],app.config['ENV'] = ‘aaa'  # 获取和设置配置文件的值
     app.config.from_object(‘settings.Foo’)  # 通过外部文件引入配置文件
    '''
     # settings.py 文件
     class 类名:
     配置文件key = 配置文件value
     # 使用 settings.py 文件,文件名任意。
     app.config.from_object(‘settings.类名’)
    # 主程序运行文件
    from flask import Flask
    from .views.account import  bpaccount # 导入视图
    from .views.code import bpcode
    app = Flask(__name__)
    app.config.from_object("settings.TestingConfig") #导入配置文件配置类
    # 读取配置文件 app.config['DEBUG']
    def create_app():
        app=Flask(__name__)
        app.config.from_object("settings.DevelopmentConfig")#导入配置文件配置类
        app.register_blueprint(bpaccount)
        app.register_blueprint(bpcode)
        return app
    # settings文件
    class Config(object): # 公共的配置类
        DEBUG =False
        SECRET_KEY="ADAFA"
        
    # 不同应用环境的不同配置类
    class ProductionConfig(Config):
        DEBUG = False
    class DevelopmentConfig(Config):
        DEBUG = False
    class TestingConfig(Config):
        TESTING=True

    六、路由系统

    6.1、endpoint 的使用

    from flask import Flask, url_for
    app = Flask(__name__)
     # endpoint 根据名字反向生成URL '/index' 。如果不设置默认为函数名 url_for( 'index')
    @app.route('/home',methods=['GET'],endpoint='n1')
    def index():
        print(url_for('n1',name=124)) # 反向生成的URL
        return 'Index'
    # app.add_url_rule('/home',view_func=index,methods=['GET'],endpoint='n1') # 第二种定义路由的方法
    if __name__ == '__main__':
        app.run(debug=True) # 修改自动重启Flask
    '''
     url_for('n1',name=124)
     输出:/home?name=124
    '''

    6.2、路由传参

     '''
      动态路由:
       /index/<int:nid> 只接收整数
       /index/<float:nid> 接收浮点数
       /index/<name> 接收字符串,自定义
       /index/默认为字符串 
     '''
    from flask import Flask,request,render_template as render,redirect,session,make_response as response,url_for
    app = Flask(__name__,static_url_path='/static/')
    @app.route('/<int:nid>',methods=['GET','POST'])
    # @app.route('/<aname>/<int:aid>',methods=['GET','POST'])
    def index(nid):
        print(url_for('index',nid=777))
     # print(url_for('index.n1',aname=aname,aid=aid))
        if request.method == 'POST':
            user = request.form.get('user')
            pwd = request.form.get('pwd')
        if user == 'admin' and pwd == '123':
            return render('index.html',success='提交成功!')
            return render('index.html',h1='首页')
        if __name__ == '__main__':
            app.run()
     '''
     输出:/index/777
     '''

    6.3、 route() 参数

    rule # URL规则
    view_func # 视图函数名称
    methods=['GET'] # 请求的方式
    endpoint=None # 名称用于反向生成URL,即:url_for('名称')
    strict_slashes=None # 对URL最后的 ‘/’ 符号是否严格要求 True:严格要求 False:不严格要求
    redirct_to='/new/<int:nid>' # 重定向
     
        app.config['SERVER_NAME'] = ‘主域名’
        subdomain='url' # 配置主域名下子域名访问地址,写入'<username>'表示任意子域名

    6.4、自定义正则

    from flask import Flask,render_template as render,url_for
    from werkzeug.routing import BaseConverter
    app = Flask(__name__,static_url_path='/static',static_folder='static')
    # 自定义正则转换器
    class RegexConverter(BaseConverter):
        def __init__(self, map, *args):# map 路由传入的路径集合
            super(RegexConverter, self).__init__(map)
            # 将接受的第1个参数当作匹配规则进行保存
            self.regex = args[0]
        def to_python(self, value):# 正则匹配URL时触发
            return int(value) # value为匹配到的值
        def to_url(self, value): # 方向生成URL触发
            val = super(RegexConverter, self).to_url(value)
            return val # url_for() nid 的值
    # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: reg
    app.url_map.converters['reg'] = RegexConverter
    @app.route('/<reg("\d+"):nid>',methods=['GET','POST'])
    def index(nid):
        print(url_for('index',nid=222))
        return render('index.html',h1='index')
    if __name__ == '__main__':
        app.run()

    6.5、浏览器请求URL,Flask视图函数访问流程

    6.5.1、循环引用的执行流程

    一文让你深入了解Flask框架

    6.5.2、找不到视图函数的解释

    为什么循环引用后,无法找到视图函数?

    在上图中执行流程中执行了两次 app = Flask(__name__),第一次在fisher主执行流程时,app被赋值一次,但是在book引用fisher主执行文件以后再次执行了 app = Flask(__name__),这样fisher主执行流程的app被后执行的book引用app所覆盖,所以当book引用中流程执行到 if 跳到主执行流程继续执行时, app 已经是 book 模块的赋值,因此就会找不到视图函数。

    可以通过 id() 打印app的内存地址来查看两个app是否是同一个app。

    七、FBV 视图

    FBV 视图:利用函数与路由建立关联,实现请求响应的控制。 CBV 视图:通过定义类的方式来建立视图与路由的关联。

    # CBV视图
    from flask import Flask,views
    app = Flask(__name__,static_url_path='/static',static_folder='static')
    class UserViews(views.MethodView):
        methods = ['GET'] # 设置请求方式
        decorators = [] # 设置装饰器(全部) 
        def get(self,*args,**kwargs):
            return 'GET'
        def POST(self,*args,**kwargs):
            return 'POST'
    app.add_url_rule('/index',None,UserViews.as_view('uuu'))
    if __name__ == '__main__':
        app.run()

    7.1、请求相关request

    下面是request可使用的属性,其中'*'是比较常用的。
    *form 
    一个从POST和PUT请求解析的 MultiDict(一键多值字典)。
    *args 
    MultiDict,要操作 URL (如 ?key=value )中提交的参数可以使用 args 属性:
    searchword = request.args.get('key', '')
    *values 
    CombinedMultiDict,内容是form和args。 
    可以使用values替代form和args。
    *cookies 
    顾名思义,请求的cookies,类型是dict。
    stream 
    在可知的mimetype下,如果进来的表单数据无法解码,会没有任何改动的保存到这个·stream·以供使用。
    很多时候,当请求的数据转换为string时,使用data是最好的方式。这个stream只返回数据一次。
    *headers 
    请求头,字典类型。
    *data 
    包含了请求的数据,并转换为字符串,除非是一个Flask无法处理的mimetype。
    *files 
    MultiDict,带有通过POST或PUT请求上传的文件。
    environ 
    WSGI隐含的环境配置。
    *method 
    请求方法,比如POST、GET。
    path
    .script_root
    .url
    .base_url
    .url_root 
    如果用户请求如下URL: 
    http://www.example.com/myapplication/page.html?x=y

    以上的参数内容如下:

    一文让你深入了解Flask框架

    is_xhr 
    如果请求是一个来自JavaScript XMLHttpRequest的触发,则返回True,这个只工作在支持
    X-Requested-With头的库并且设置了XMLHttpRequest。
    blueprint 
    蓝本名字。
    endpoint 
    endpoint匹配请求,这个与view_args相结合,可是用于重构相同或修改URL。当匹配的时候发生异常,会返回None。
    get_json(force=False, silent=False, cache=True)
    json 
    如果mimetype是application/json,这个参数将会解析JSON数据,如果不是则返回None。 
    可以使用这个替代get_json()方法。
    max_content_length 
    只读,返回MAX_CONTENT_LENGTH的配置键。
    module
    如果请求是发送到一个实际的模块,则该参数返回当前模块的名称。这是弃用的功能,使用blueprints替代。
    on_json_loading_failed(e)
    routing_exception = None 
    如果匹配URL失败,这个异常将会/已经抛出作为请求处理的一部分。这通常用于NotFound异常或类似的情况。
    url_rule = None 
    内部规则匹配请求的URL。这可用于在URL之前/之后检查方法是否允许(request.url_rule.methods) 等等。 
    默认情况下,在处理请求函数中写下 print('request.url_rule.methods', request.url_rule.methods) 
    会打印:
    request.url_rule.methods {‘GET’, ‘OPTIONS’, ‘HEAD’}
    view_args = None 
    一个匹配请求的view参数的字典,当匹配的时候发生异常,会返回None。

    7.2、响应相关

    from flask import Flask,make_response as response,jsonify,render_template as render,redirect
    '''
        make_response 封装所有形式的返回响应体,并可以设置返回响应头
        res = response(render('index.html',**{'k1':'v1'}))
        return res
        返回响应体
        return '' 返回字符串
        return jsonify({'k1':'v1'}) 返回json字符串
        return render('index.html',**{'k1':'v1'}) 返回一个文件
        return redirect('http://www.baidu.com') 返回重定向URL
    '''
    app = Flask(__name__,static_url_path='/static/')
    app.secret_key = 'abck'
    @app.route('/',methods=['GET','POST'])
    def index():
        res = response('index.html')  # 封装了返回字符串响应体
        res.headers['xxx'] = 123 # 设置返回响应头
        res.set_cookie = 321 # 设置cookies
        return res # 返回请求体,请求头,
    if __name__ == '__main__':
        app.run()

    7.3、before_request 装饰器

    from flask import Flask,make_response as response,jsonify,render_template as render,redirect,request
    app = Flask(__name__,static_url_path='/static/')
    # app.before_request后面的函数,在所有函数执行前执行。
    # app级中app.before_request(函数名)直接使用。
    # 蓝图中使用装饰器的方式
    @app.before_request 
    def func():
     if request.path == '/index':
       return None
     return '返回值'
      # 返回值不是None,不再往后执行,直接返回return的值
      # 返回None,才往后执行其他,这里执行index函数
     
    @app.route('/',methods=['GET','POST'])
    def index():
     res = response('index.html')  # 封装了返回字符串响应体
     res.headers['xxx'] = 123 # 设置返回响应头
     res.set_cookie = 321 # 设置cookies
     return res # 返回请求体,请求头,
     
    if __name__ == '__main__':
     app.run()

    八、模板渲染

    Flask 模板详解

    8.1、基本语句的使用

    # 字符串,字典,列表等基本数据类型,都可以通过python本来的方法操作。
    {{ 属性名.0 }}
    {{ 属性名[0] }}
    {{ 属性名() }}
     
    # html标签转换
    {{ html标签|safe }}
    from flask import Markup
    Markup('<h1>h1标签</h1>')
    # 设置默认
    {{ 属性名|default('你好') }}

    8.2、设置全局模板函数

    # 设置全局所用的函数
    @app.template_global()
    def sb(a1,a2):
        return a1 + a2
    # 使用:{{ sb(a1,a2) }}
     
    # 过滤filter 的使用
    @app.template_filter()
    def sb(a1,a2,a3):
        return a1 + a2 + a3
    # 使用:{{ a1|sb(a2,a3) }}

    8.3、模板的继承

    模块:{% block content %}{% endblock %}
    模板文件:
     <html>
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <link rel="stylesheet" href="{{ url_for('static',filename='index.css') }}" type="text/css">
    </head>
    <body>
        <div>
            {% block content %}{% endblock %}
            <a href="{{ url_for('admin.index',id=1234)}}">url_for跳转带参数</a>
        </div>
    </body>
     </html>
    ----------------------------------------------------------------------------------------
     <!-- 导入模板文件 -->
     {% extends './template.html' %}
     {% block content %}
      <h1> 你好 </h1>
        {{ h1 }}
     {% endblock %}
    调用模块:
    需要使用模块文件的引入: 
    {% extents '模板文件' %} 
    模块代码:
    {% block content %}
    <h1> 你好 </h1>
    {{ h1 }}
    {% endblock %}
    -------------------------------------------------------------------------------------
    导入模板:{% include '模板文件' %}
     
    宏定义:{% macro ccc(name,type='text',value='') %} # 相当于定义def 函数
    <input type="{{ type }}" name="{{ name }}"/>
    <input type="submit" value="提交"/>
    {% endmacro %}
    使用宏:{{ ccc('n1') }}

    8.4、url_for生成静态文件URL连接

    '''
    # 常规构造静态文件链接 
    1.包含可变部分的动态路由,url_for(endpoint,_external=True,**kwargs)以视图函数端点名和可选参数作为参数,
      当_external为True时返回url绝对路径,否则返回相对路径
    2.url_for(endpoint,_external=True,**kwargs)中可以为动态静态文件部分传递参数,
      如url_for('.static',_external=True,filename='js/html5shiv.min.js'),
      返回的url是http://localhost/static/js/html5shiv.min.js
    '''
    # 不在蓝图中使用 url_for 构建静态文件路径 
    # http://localhost/static/js/fixes/html5shiv.min.js 
    print url_for('static', filename='js/fixes/html5shiv.min.js', _external=True)
    '''
    PS:蓝图中endpoint必须加上当前命名空间前缀表示当前命名空间,如定义的main蓝图,必须如下使用
    url_for('main.static',_external=True,filename='js/html5shiv.min.js')
    '''
    # 蓝图中使用url_for构建反向连接时必须添加蓝图名
    # http://localhost/static/js/fixes/html5shiv.min.js 
    print url_for('.static', filename='js/fixes/html5shiv.min.js', _external=True)
    print url_for('main.static', filename='js/fixes/html5shiv.min.js', _external=True)

    8.5、错误页面设置

    定义错误页面用装饰器 @app.errorhandler() 来完成,在定义的过程中必须遵循的是在 Flask 直接实例化下定义,不然会定义不成功。

    # _*_ coding:utf-8 _*_
    from flask import Flask, render_template as render
    app = Flask(__name__)
    @app.errorhandler(404)
    def page_not_found(error):
        return render('/home/404.html'), 404

    九、Flash和特殊装饰器

    9.1、flash 消息闪现

    在使用 flash() 时会使用到session,所以需要在配置文件中配置 SECRET_KEY。

    from flask import flash,get_flashed_messages
    flash('',category='数据分类属性') # 设置
    flash('Error',category='error') 
    get_flash_messages() # 获取
    get_flash_messages(category_filter=['数据分类属性']) # 通过分类获取
    '''
    flash 实现原理:
        flash基于session来处理内容,先将flash('')中的值存入session中,再通过session的pop移除,达到用一次就消失的效果。
    '''
    # session自己实现
    session.pop('属性名')

    HTML中获取 flash() 信息

    在模板引擎中怎样定义一个变量;通过关键字 set 定义一个变量。category_filte 过滤返回的类别。

    {% set messages = get_flash_messages(category_filter=["error"]) %}

    Flask消息闪现文档

    9.2、Flask中间件

    9.2.1、特殊装饰器

    #设置全局模板函数
    @template_global()
    @template_filter()
    # app.route视图函数执行前执行,只运行第一次
    @app.before_first_request
    def x1():
        print('before_first')
    
    # app.route视图函数执行前执行,多个谁先定义谁先执行
    @app.before_requesr
    def x2():
        print('before')
    
    # app.route视图函数执行后执行,必须有参数和返回值,多个谁后定义谁先执行
    @app.after_request
    def x3(response):
        print('after')
    return response
    
    #定义404
    @app.errorhandler(404) 
    def not_fourd(arg):
        return '404'

    9.2.2、中间件

     '''
      Flask的中间件需要通过自定义方法,去替换源码中的相关方法,利用在程序获得请求时才运行__call__()的特性,
      来创建中间件,从而完成中间件的功能。
     '''
    class Middleware(object):
     def __init__(self, old):
         self.old = old
     def __call__(self, *args, **kwargs):
         print('前')
         ret = self.old(*args, **kwargs)
         print('后')
         return ret
       
    if __name__ == '__main__':
        app.wsgi_app = Middleware(app.wsgi_app)

    十、蓝图

    为开发者提供一个目录结构,让开发更规范,可以将特殊装饰器加到蓝图中,并根据不同的返回内容设置不同的域名前缀。

    为什么flask的根目录不是第一个flask03,而是第二个flask03?

    因为在对 Flask(__name__) 进行实例化时,__name__ 所获取的值决定了Flask根目录的位置。

    10.1、蓝图的基本模型

    一文让你深入了解Flask框架

    10.1.1、主路由视图函数

    __init__.py

    from flask import Flask
    # 导入定义的蓝图模块
    from .views.index import n
    def app_view():
        app = Flask(__name__,)
        # 注册,url_prefix指定打开URL的访问集 http://127.0.0.1/app/1 http://127.0.0.1/app/2 
        app.register_blueprint(n,url_prefix='/app')# 添加了url_prefix 模板文件静态文件也需要添加'/app'
        return app

    app.py

    from flask03 import app_view
    app = app_view()
    print(app)
    if __name__ == '__main__':
        app.run()

    10.1.2、分路由视图函数

    index.py

    #coding:utf8
    from flask import Blueprint
    # ps:蓝图名不能与视图函数名一致
    n = Blueprint('index',__name__,template_folder='../xxx',
    static_folder='../statics',static_url_path='/statics')
    '''
     在蓝图中,必须带上“蓝图函数.endpoint名”
     url_for('index.n1',name=name)
     url_for('.n1',name=name)
    '''
    @n.route('/home/<name>',methods=['GET'],endpoint='n1')
    def index(name):
        print(name)
        print(url_for('index.n1',name=name))
        return 'home'
    '''
     访问域名:http://127.0.0.1:5000/api/home/123
     输出:“name”:123
        “url_for('index.n1',name=name)”:/api/home/123
    '''

    10.2、大项目蓝图目录结构

    一文让你深入了解Flask框架

    十一、Flask上下文管理

    11.1、Flask执行顺序

    上下文管理的内容:
    request、session、app、g
    1、客户端请求到来时,会将request/session封装到一个对象 RequestContext(self,environ)中(其中self为app对象,
    environ为客户端请求的原始数据);
    ctx=RequestContext(self,environ) 封装了 request/session 
    2、将含有request/session的对象打包,根据线程/协程的唯一标识,作为字典存放在一个
    “空间中”(线程/协程唯一标识作为Key,RequestContext对象作为Value),
    {
    线程/协程唯一标识:{ctx:RequestContext对象}
    ....
    }
    3、视图函数运行过程
    from flask import request,session
    request.method
    当有请求过来时,通过线程/协程唯一标识找到,存放在空间中的RequestContext对象,再通过对象找到封装其中的
    request/session,最后找到属性.method。
    4、请求结束
    session保存到浏览器cookie中,并移除字典中的数据,从而结束请求。

    11.2、偏函数

    import functools
    def index(a1,a2):
        return a1+a2
    # 函数常规的用法
    a = index(12,20)
    print(a)
    '''
     利用 functools 模块实现偏函数;
     偏函数只要传入一个值,其他的值自动传入
    '''
    new_func = functools.partial(index,666)
    a1 = new_func(34)
    print(a1)

    11.3、上下文:执行流程

    request 请求执行流程

    一文让你深入了解Flask框架

    11.4、上下文session

    Flask session 的请求流程

    十二、Flask 中的 localProxy 方法

    local:维护保存在__storage__字典中的线程/进程;

    localStack:视图系统通过其操作local维护的__storage__字典;

    localProxy:它的作用主要是帮助 request 获取当前应用的HTTP请求信息,伴 request 运行和消失的。

    class LocalProxy(object):
        def __init__(self):
            pass
        def __getattr__(self):
            pass
        def __setattr__(self):
            pass
        def __getitem__(self):
            pass
    
    lp = LocalProxy()

    十三、Flask g变量

    1、g作为flask程序全局的一个临时变量,充当着中间媒介的作用,我们可以通过它传递一些数据;

    2、g保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别;

    3、g对象在一次请求中的所有代码任何地方,都是可以使用的。

    g.name='abc'

    g变量简单应用

    1、创建一个utils.py文件,用于测试除主文件以外的g对象的使用

    # utils.py
    #encoding: utf-8
    from flask import g
    def login_log():
        print u'当前登录用户是:%s' % g.username
    def login_ip():
        print u'当前登录用户的IP是:%s' % g.ip

    2、在主文件中调用utils.py中的函数

    #encoding: utf-8
    from flask import Flask,g,request,render_template
    from utils import login_log,login_ip
    app = Flask(__name__)
     
    @app.route('/')
    def hello_world():
        return 'Hello World!'
        
    @app.route('/login/',methods=['GET', 'POST'])
    def login():
    if request.method == 'GET':
    return render_template('login.html')
    else:
    username = request.form.get('username')
    password = request.form.get('password')
    g.username = username
    g.ip = password
    login_log()
    login_ip()
    return u'恭喜登录成功!'
     
    if __name__ == '__main__':
        app.run()

    python学习网,大量的免费python视频教程,欢迎在线学习!


    起源地下载网 » 一文让你深入了解Flask框架

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元