python3-开发进阶Flask的基础

发布时间:2019-03-02 10:49:08编辑:auto阅读(2240)

     一、概述

    最大的特点:短小精悍、可拓展强的一个Web框架。注意点:上下文管理机制,依赖wsgi:werkzurg 模块

    二、前奏学习werkzurg

    先来回顾一个知识点:一个类加括号会执行__init__方法,一个对象加括号执行__call__方法

    事例1:

    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)
    
    #封装了请求和相应的对象

    flask就是基于上面一步一步搭建起来的!

     

    三、学习flask

    第一个flask:

    from flask import Flask
    
    duo=Flask(__name__)
    
    duo.run()   

    三行  启动了程序,但是访问url,发现是Not  Found  !!!

    什么原因呢?按理说访问url,执行函数,返回结果,我们发现我们访问了,但是没有接收,在django应该怎么写,写个路由写个视图,在这也是一样

    from flask import Flask
    
    duo=Flask(__name__)
    
    @duo.route('index')
    def index():
        return "hello world"
    
    duo.run()  
    
    #这下执行就访问成功

    这个duo.run 就是启动socket,这个脚本要以主函数去运行的时候,采取执行duo.run,别人如果导入的时候,run是不应该执行的:

    from flask import Flask
    
    duo=Flask(__name__)
    
    @duo.route('index')
    def index():
        return "hello world"
    
    if __name__ == '__main__': 
        duo.run()

    一个flasl实现简单的登录:

    from flask import Flask,render_template,request,redirect,session 
    
    duo=Flask(__name__)
    duo.secret_key='shuai'   #加密方式
    
    @duo.route('/login',methods=['GET','POST'])    #默认GET 别的请求还要添加
    def login():
    
        if request.method == 'GET':
            #return 'Login'   #HttpResponse  django    返回字符串
            return render_template('login.html')
        #request.form ----------》#request.POST
        #request.args ----------》 #request.GET
        user=request.form.get('user')
        pwd=request.form.get('pwd')
        if user=='duoduo' and pwd =='123':
            session['user']=user
            return redirect('/index')
        return render_template('login.html',error='用户名或密码错误')
    
    @duo.route('/index')
    def index():
        user=session.get('user')
        if not user:
            return redirect('login')
        return render_template('index.html')
    
    
    if __name__ == '__main__':
        duo.run()

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
        <h1>用户登入</h1>
        <form method="post">
            <input type="text" name="user">
            <input type="password" name="pwd">
            <input type="submit" value="提交">{{error}}
        </form>
    
    </body>
    </html>

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
    </head>
    <body>
        <h1>欢迎使用</h1>
        <img src="/static/111.jpg" alt="">   #图片自己找个
    </body>
    </html>

    三、Flask

    1、简介

    1、配置文件                                                                                           

        模块+静态文件         Flask(__name__,...) 

    2、路由系统     装饰器实现的

        @duo.route('/index',methods=['GET'])

    3、视图             也有fbv,cbv

    4、请求相关      导入就能用,django 而是参数

    request.form 

    request.args

    request.method

    5、响应

    字符串‘’

    render

    redirect

    6、模块渲染

    7、session

    session['xxx']=123

    session.get('xxx')

    8、fiash   (闪现)

    9、中间件     基本不用  请求前的操作

    10、特殊的装饰器

     

    假使一个setting.py:

    class Foo:
        DEBUG=True
        TEST=True

    一个脚本duoduo.py

    path='setting.Foo'

    我们如何在path中将Foo这个类找到?如何获取其中大写的静态字段的值:

    import importlib
    
    path='setting.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))
    
    #其实这就是配置文件导入原理
    答案

    2、详解

    1、配置文件

    flask的配置文件在哪里呢?这些都是默认的配置文件,

    from flask import Flask
    
    duo=Flask(__name__)
    
    print(duo.config)
    
    #<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 
    'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31),
    'USE_X_SENDFILE': False, 'SERVER_NAME': None, '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,
    'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), '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}>

    配置文件是可以修改的,那在哪里改?我们这有这样一个语法:

    duo.config.from_object('setting.Foo')  #还是上面的setting.py文件

    我们来看看.from_object 中的源码:

     

     

     

    我们以后的配置文件,可以生成不一样的类,开发环境一个类,线上环境一个类,相同的静态属性一个类,我们根据现实的环境只需改一个类名字就可以了

     

    2、路由系统

    @duo.route(url,methods(允许请求的方式),endpoint(值))

    -endpoint   ,反向生成URL,如果没有endpoint设定的值,那么默认的这就是函数名

    -url_for('endpoint设定的值')

    from flask import Flask,url_for
    
    duo=Flask(__name__)
    
    # print(duo.config)
    duo.config.from_object('setting.Foo')
    # print(duo.config)
    
    
    
    @duo.route('/index/',methods=['GET','POST'])   #endpoint就是django反向生成的name,如果不写endpoint,url_for后面的值就是函数名
    def index():
        print(url_for('index'))   #反向生成url
        return "hello world"
    
    if __name__ == '__main__':
        duo.run()

     我们在django中有的时候url会带上对象的nid值,这个在flask中是什么的格式呢?

    • @duo.route('/user/<username>')      字符串
    • @duo.route('/post/<int:post_id>')      整数
    • @duo.route('/post/<float:post_id>')    浮点
    • @duo.route('/post/<path:path>')       路径
    • @duo.route('/login', methods=['GET', 'POST'])

    但是默认是不支持正则!   

    这就是动态的路由

    from flask import Flask,url_for
    
    duo=Flask(__name__)
    
    # print(duo.config)
    duo.config.from_object('setting.Foo')
    # print(duo.config)
    
    @duo.route('/index/<int:nid>',methods=['GET','POST'])   #int是用来约束在url的值
    def index(nid):
        print(nid)
        print(url_for('index',nid=1))     #有参数要加参数
        return "hello world"
    
    if __name__ == '__main__':
        duo.run()

     

    3、FBV(CBV后面再介绍)

    4、请求相关,响应相关

    from flask import Flask,jsonify,make_response
    
    duo=Flask(__name__)
    @duo.route('/index/<int:nid>',methods=['GET','POST'])   #int是用来约束在url的值
    def index(nid):
        # 请求相关信息
        # 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))

    # 响应相关信息 # return "字符串" # return render_template('html模板路径',**{}) # return redirect('/index.html') # return jsonify({'k1':'v1'}) #jsonify帮你序列化 obj=make_response('Index') #把返回给用户的字符串,封装到这个对象 obj.headers['duoduo']=666 #设置响应头 return obj if __name__ == '__main__': duo.run()

    运行后:

    6、模板的渲染

    一个登入验证,可以导入before_request,没有返回值就是可以通过,有返回值就无法通过

    from flask import Flask,request,before_request,session
    
    duo=Flask(__name__)
    
    @duo.before_request
    def xxxxx():
        if request.path =='/login':  #只有登入视图可以访问
            return None
        if session.get('user') :
            return None
    
        return redirect('login')  #  上面不通过,返回登入页面

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

    -传入函数

    django,自动执行

    flask,不自动执行

    -全局定义函数

    @duo.template_global()

    @duo.template_filter()

    -模板的继承

    {%extends '给谁'%}

    {%block content%}

    {% endblock%}

    -include  直接加页面

    -安全方式展示

    前端:{{obj|safe}}

    后端:Markup('obj')

     

    7、session 

    session在视图中可以字典来使用,为什么能当作字典,我们来看一下源码:

    from flask.sessions import SecureCookieSession

     继承了dict,不用多说什么

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

    当请求结束时:flask会读取内存中字典的值,在进行序列化+加密,写入到用户的cookie中。(这就是session的机制)

     session的配置是可以改的,关于session有以下几点:

     'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),     #生命周期
    'SESSION_COOKIE_NAME':                  'session'  #名称
    'SESSION_COOKIE_DOMAIN':                None    #域名
    'SESSION_COOKIE_PATH':                     None       #路径
    ‘SESSION_COOKIE_HTTPONLY':             True    #支持HP读取
    'SESSION_COOKIE_SECURE':                False  #安全性
    'SESSION_REFRESH_EACH_REQUEST':   True    #最后一次访问的时间保持

    8、flash

    在session中存储一会数据,读取时通过pop将数据移除,以此来创造一个效果,只存一次,只能取一次

    实例:

    from flask import Flask,flash,get_flashed_messages
    
    duo=Flask(__name__)
    duo.secret_key='duoduo'   #这是一个容易忘记的点
    #出现secret_key 的报错就是这个设置
    
    @duo.route('/page1')
    def page1():
        flash('大娃','boy')   
        flash('二娃','boy')
        flash('蛇精','girl')
        return 'session'
    
    @duo.route('/page2')
    def page2():
        print(get_flashed_messages(category_filter=['boy']))
    
        return 'session'
    
    if __name__ == '__main__':
        duo.run()

    访问一下,取一下,我们来看看源码:

     

     

     9、中间件

    那我们先来了解一下flask是怎么运行起来的:

    先写一个简单的脚本:

    from flask import Flask
    duo=Flask(__name__)
    
    @duo.route('/index')
    def index():
        print('index')
        return 'Index'
    
    if __name__ == '__main__':
        duo.run()

    首先,先点开源码的duo.run:

      

    run的self就是flask的对象,请求进来第三给参数后面加括号,是不是flask的对象加括号,就是调用,对象调用执行__call__方法:

    duo.__call__  #进去看看

    当上面的脚本运行,只有请求访问,才执行__call__方法

    一个简单的应用

    from flask import Flask
    
    duo=Flask(__name__)
    
    @duo.route('/index')
    def index():
        print('index')
        return 'Index'
    
    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__':
        duo.wsgi_app=Middleware(duo.wsgi_app)   
        duo.run()

     

    10、特殊的装饰器(重点)

    before_request   #谁先定义执行

    after_request   #从后往上执行

    这上面两个原理就是把函数名放到一个列表,然后循环的机制

    from flask import Flask
    
    duo=Flask(__name__)
    
    
    @duo.before_request
    def x1():
        print('before')
    
    @duo.after_request
    def x2(reponse):    #这里必须要有返回值
        print('after')
        return reponse
    
    @duo.route('/index1')
    def index1():
        print('index')
        return 'Index'
    
    @duo.route('/order')
    def order():
        print('order')
        return 'order'
    
    if __name__ == '__main__':
        duo.run()

    这里有一个注意点就是,before_request有返回值的话,要走所有的after_request ,在django1.9以前都只是这个流程,后来改了机制,

    我们发现1.10以后,走最外面一个中间件就返回。

     

    before_first_request      #只执行启动起来 首次,后就不再执行,后面详细看源码

    template_global    #  渲染 全局定义函数

    template_filter     #   不一样的全局定义函数

     errorhandler   #定制错误信息

    @duo.errorhandler(404)
    def not_found(arg):
        print(arg)
        return '没找到'    #定制错误信息的页面比较常用

     

关键字