• Flask


    Flask框架简介

    说明:
    flask是一个轻量级的web框架,被称为微型框架。只提供了一个高效稳定的核心,其它全部通过扩展来实现。意思就是你可以根据项目需要进行量身定制,也意味着你需要不断学习相关的扩展库。

    核心:

    WSGI系统、调试、路由

    模板引擎(Jinja2,是flask核心开发者人员发开的)

    安装:

    >: pip install flask

    werkzeug简介

    Flask的socket是基于Werkzeug 实现的

    Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。这里稍微说一下, werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等

    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运行的本质:

    from flask import Flask
    # 实例化产生一个Flask对象
    app = Flask(__name__)
    # 装饰器路由
    @app.route('/')
    def index():
        return 'ok'
    
    if __name__ == '__main__':
        # 本质是 run_simple(host, port, app, **options)
        # app() 调用的是Flask的__call__里的wsgi_app方法,返回response
        app.run()

    启动参数
    参数 说明
    debug 是否开启调试模式,默认为False;开启后会有出错调试信息,文件会自动加载。
    threaded 是否开启多线程,默认为Flase。
    host 指定主机,默认为’127.0.0.1’,设置为’0.0.0.0’后可以通过IP进制访问
    port 指定端口,默认为5000。
    启动示例:app.run(debug=True, threaded=True, host=‘0.0.0.0’, port=5555)

    响应四剑客 render_template,redirect,jsonify

    • 返回字符串

    @app.route('/')
    def index():
        # 1 直接返回字符串
        return 'ok'
    • 返回HTML 

    from flask import Flask, render_template
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        # 2 返回HTML
        return render_template('index.html')  # 参数: xxx.HTML
    • 跳转页面(重定向)

    from flask import Flask, redirect
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        # 3 跳转页面
        return redirect('/login')  # 参数: url
    
    @app.route('/login')
    def login():
        return render_template('login.html')  
    • 返回json数据

    from flask import Flask, jsonify
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        # 4 返回json数据
        dic = {'name':'xionger', 'age': 20}
        return jsonify(dic)  # 参数: 要序列化的数据

    templates(模板层)

    1. 创建templates文件夹
    2. 文件夹内创建HTML文件
    • 视图函数向HTML页面传递数据

    # 方式一
    @app.route('/') def index(): dic = {'name': 'xionger', 'age': 20} return render_template('index.html', num=100, dic_data=dic)
    # 方式二
    from flask import Flask, render_template, Markup
    app = Flask(__name__)
    
    def func(t1, t2):
        return Markup(f'<h1>hahaha{t1}{t2}</h1>')
    
    @app.route('/list',methods=['GET'])
    def list():
        return render_template('list.html',html="<h1>hahaha</h1>", func=func)
    
    # list.html
        {{ html|safe }}
        {{ func(1, 2) }}
    • 模板语法

    <body>
        <p>{{ num }}</p>  100
        <p>{{ dic_data.name }}</p>  xionger
        <p>{{ dic_data.get('name') }}</p>  xionger
        <p>{{ dic_data['name'] }}</p>  xionger
    </body>
    <!-- 字典, 列表等数据类型在python中如何使用, 在模板中就如何使用 -->
    <!-- 遍历循环 -->
    <body>
        <h1>用户列表</h1>
        <table>
            {% for k,v in user_dict.items() %}
            <tr>
                <td>{{k}}</td>
                <td>{{v.name}}</td>
                <td>{{v['name']}}</td>
                <td>{{v.get('name')}}</td>
                <td><a href="/detail/{{k}}">查看详细</a></td>
            </tr>
            {% endfor %}
        </table>
    </body>
    <!-- 逻辑判断 -->
    <body>
        <h1>用户列表</h1>
        <table>
            {% if name %}
              <h1>Hello {{ name }}!</h1>
            {% else %}
              <h1>Hello World!</h1>
            {% endif %}
        </table>
    </body>

    配置文件

    • 方式一

    # 这中方式只能配置两种
    app.debug=True
    app.secret_key="123123"
    • 方式二 :使用config字典

    app.config['DEBUG']=True
    • 方式三: 导入文件(插拔式)

    settings.py
    # DEBUG = True
    
    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
    视图函数文件.py
    app.config.from_object('settings.DevelopmentConfig')

    补充:

    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,
        }

    路由系统

    @setupmethod
        def add_url_rule(
            self,
            rule,  # --> 装饰器里的路由
            endpoint=None,  # --> 路由别名
            view_func=None,  # --> 视图函数
            provide_automatic_options=None,
            **options  # 用来接收methods等参数的字典
        ):
            
            if endpoint is None:  # 若路由没有起别名
                # endpoint = 视图函数的名字
                endpoint = _endpoint_from_view_func(view_func)
            # 将endpoint添加到options里
            options["endpoint"] = endpoint
            # 获取methods的值
            methods = options.pop("methods", None)
    
            # if the methods are not given and the view_func object knows its
            # methods we can use that instead.  If neither exists, we go with
            # a tuple of only ``GET`` as default.
            if methods is None:  
                # methods为空 则默认是GET请求
                methods = getattr(view_func, "methods", None) or ("GET",)
            if isinstance(methods, string_types):
                raise TypeError(
                    "Allowed methods have to be iterables of strings, "
                    'for example: @app.route(..., methods=["POST"])'
                )
            methods = set(item.upper() for item in methods)
    
            # Methods that should always be added
            required_methods = set(getattr(view_func, "required_methods", ()))
    
            # starting with Flask 0.8 the view_func object can disable and
            # force-enable the automatic options handling.
            if provide_automatic_options is None:
                provide_automatic_options = getattr(
                    view_func, "provide_automatic_options", None
                )
    
            if provide_automatic_options is None:
                if "OPTIONS" not in methods:
                    provide_automatic_options = True
                    required_methods.add("OPTIONS")
                else:
                    provide_automatic_options = False
    
            # Add the required methods now.
            methods |= required_methods
    
            rule = self.url_rule_class(rule, methods=methods, **options)
            rule.provide_automatic_options = provide_automatic_options
    
            self.url_map.add(rule)
            if view_func is not None:
                old_func = self.view_functions.get(endpoint)  # endpoint 是视图函数的名字
                if old_func is not None and old_func != view_func:
                    raise AssertionError(
                        "View function mapping is overwriting an "
                        "existing endpoint function: %s" % endpoint
                    )
                # 若view_functions中有endpoint 则取出赋值给view_func
                # view_func要么必须有值, 要么endpoint有别名, 最终endpoint的值也会赋值给view_func
                self.view_functions[endpoint] = view_func  
                # 如果endpoint有别名 view_func = endpoint
                # 如果endpoint没有有别名 view_func = endpoint(视图函数名字)
    路由系统源码
    • 典型装饰器写法

    from flask import Flask
    app = Flask(__name__)
    
    # 路由装饰器配置该函数的路由
    @app.route('/index/<int:nid>',methods=['GET'],endpoint='haha')
    def index(nid):
        return nid
    '''
    '/index/<int:nid>'  # 路由有名分组,视图函数要接收
    methods  # 该视图函数可以用的请求方式
    endpoint  # 路由别名反向解析, 在其他视图函数中用: real_url=url_for("别名") 调用该函数
          endpoint默认指定的是函数名字 核心源码: route -> decorator -> add_url_rule flask路由基于装饰器,本质是基于:add_url_rule add_url_rule 源码中,endpoint如果为空, endpoint = _endpoint_from_view_func(view_func),最终取view_func.__name__(函数名)
    '''
    • add_url_rule 

    app.add_url_rule参数:
    - rule, URL规则
    - view_func, 视图函数名称
    - defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}为函数提供参数
    - endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
    - methods = None, 允许的请求方式,如:["GET", "POST"]
    - redirect_to = '/login'  重定向到指定的地址 可以是路径也可以是别名
    - strict_slashes  严格模式
            @app.route('/index', strict_slashes=False)
            #访问http://www.xx.com/index/ 或http://www.xx.com/index均可
            @app.route('/index', strict_slashes=True)
            #仅访问http://www.xx.com/index
    def index(nid):
        return nid
    
    app.add_url_rule('/index/<string:nid>',view_func=index,endpoint="haha",methods=['POST',"GET"])

    补充: 别名使用

    def login():
        return 'login'
    app.add_url_rule('/login',view_func=login, endpoint="haha", methods=['POST',"GET"])
    
    
    def index(nid):
        real_url = url_for('haha')
    print(real_url) # /login
    return real_url app.add_url_rule('/index/<string:nid>',view_func=index,methods=['POST',"GET"])

    注意: 别名不能重复,一个路由一个别名
    •  支持正则

    1 写类,继承BaseConverter
    2 注册:app.url_map.converters['regex'] = RegexConverter
    3 使用:@app.route('/index/<regex("d+"):nid>')  正则表达式会当作第二个参数传递到类中
    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):
            """
            路由匹配时,匹配成功后传递给视图函数中参数的值
            """
            #value就正则匹配出来的结果
            # print('value',value,type(value))
            return value
    
        def to_url(self, value):
            """
            使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
            """
            val = super(RegexConverter, self).to_url(value)
            # print(val)  # 666
            return val
    
    app.url_map.converters['regex'] = RegexConverter
    @app.route('/test/<regex("d+"):nid>',endpoint="tes")
    def test(nid):
        print("nid",nid,type(nid))
        print(url_for('tes', nid='666'))  # /test/666
        return 'test'

    CBV

    as_view 源码

    @classmethod
        def as_view(cls, name, *class_args, **class_kwargs):  # cls = 视图类 name一定要传值
    
            def view(*args, **kwargs):
                # view_class = cls 视图类
                self = view.view_class(*class_args, **class_kwargs)  # self 是视图类对象
                # self调用dispatch_request方法,调用的是视图类中的dispatch_request方法
                return self.dispatch_request(*args, **kwargs)
    
            if cls.decorators:
                view.__name__ = name
                view.__module__ = cls.__module__
                for decorator in cls.decorators:
                    view = decorator(view)
    
            # 在 view的名称空间中添加下面的键值对
            view.view_class = cls
            view.__name__ = name
            view.__doc__ = cls.__doc__
            view.__module__ = cls.__module__
            view.methods = cls.methods
            view.provide_automatic_options = cls.provide_automatic_options
            return view
    as_view -> view(View中的) -> dispatch_request(视图类中的)
    • 普通使用

    from flask import Flask, views
    app = Flask(__name__)
    
    class IndexView(views.View):
        methods = ['POST', 'GET']
        # decorators = [ ]
        def dispatch_request(self):
            print('Index')
            return 'Index'
    
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))
    '''
    methods = []  视图类的请求方式, 默认GET, 若指定了请求方式,就只能用指定的方式请求该视图类
    as_view(name='index')  要指定name = 别名, 若不指定,导致所有的路由都是view,别名一样报错
    
    '''

    MethodView 源码

    class MethodView(with_metaclass(MethodViewType, View)):
        # 重写dispatch_request方法
        def dispatch_request(self, *args, **kwargs):  # self是视图类的对象
            # 从self中获取request中的请求方式,并改成小写
            meth = getattr(self, request.method.lower(), None)  # 核心 使前端请求方式与视图类中的请求方式对应
    
            # If the request method is HEAD and we don't have a handler for it
            # retry with GET.
            # 如果 meth是空并且请求方式是HEAD
            if meth is None and request.method == "HEAD":
                # 从self中获取get方法
                meth = getattr(self, "get", None)
            # meth为空抛出错误
            assert meth is not None, "Unimplemented method %r" % request.method
            # 当前端的请求方式在视图类中有时,
            # meth不为空,并调用meth映射的请求方式,返回
            # 否则meth为空抛出异常
            return meth(*args, **kwargs)
    as_view -> view(View中的) -> dispatch_request(MethodView中的)
    • 指定post / get

    class LoginView(views.MethodView):
        # methods = ['GET']  # 默认支持 GET/POST ,若指定请求方式,该视图类只能用指定的方式
        def get(self):
            print('get')
            return 'get'
        def post(self):
            print('post')
            return 'post'
    
    app.add_url_rule('/login', view_func=LoginView.as_view(name='login'))
  • 相关阅读:
    mysq foreign外键记录
    查询时隐藏部分身份证号
    SpringBoot接收前端参数
    RabbbitMQ安装
    @configurationProperties注解时 idea弹出 Spring Boot Annotion processor not found in classpath
    rpm,yum和apt使用详解
    python人脸识别
    Fuchsia文章汇总
    Androi O Automotive 介绍
    Linux 版本控制工具之rabbitvcs
  • 原文地址:https://www.cnblogs.com/waller/p/11837979.html
Copyright © 2020-2023  润新知