• Flask


    一、基本使用

    安装:

    pip3 install flask

    基本使用:

    from flask import Flask, request, render_template, redirect, session
    
    app = Flask(__name__, template_folder="templates", static_folder="static")
    app.secret_key = "abc"
    
    @app.route("/login", methods=["GET", "POST"])
    def login():
        if request.method == "GET":
            return render_template("login.html")
        username = request.form.get("username")  # 如果是get请求 request.args
        password = request.form.get("password")
        if username == "pd" and password == "123":
            session["user"] = username
            return redirect("/index")
        # return render_template("login.html", error="用户名或密码错误")
        return render_template("login.html", **{"error": "用户名或密码错误"})
    
    @app.route("/index")
    def index():
        user = session.get("user")
        if not user:
            return redirect("/login")
        return render_template("index.html")
    
    if __name__ == "__main__":
        app.run()

    二、配置文件

    flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
        {
            'DEBUG':                                False,  # 是否开启Debug模式
            'TESTING':                              False,  # 是否开启测试模式
            'PROPAGATE_EXCEPTIONS':                 None,                          
            'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
            'SECRET_KEY':                           None,
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),  # session超时时间
            '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,
        }
    View Code

    配置方式1:

    app.config["DEBUG"] = True
    # 由于Config对象本质上是字典,所以还可以使用
    app.config.update({"DEBUG": "True"})

    配置方式2:

    新建一个 settings.py 文件,例如:

    # 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

    再使用:app.config.from_object("配置文件类的路径")

    所以,生产环境就用生产环境的配置,开发时就用开发环境的配置。

    三、路由系统

    @app.route("/index", endpoint="xx")  #  endpoint相当于别名
    def index():
        print(url_for("xx"))  # /index  url_for("xx"),反向生成url,默认url_for("函数名")
        return "index"
    @app.route("/index/<user>")  # 字符串
    @app.route("/index/<int:id>")
    @app.route("/index/<float:id>")
    @app.route("/index/<path:path>")
    @app.route("/login", methods=["GET", "POST"])
    # 示例:
    @app.route("/index/<user>")
    def index(user):
        return user
    # 常用路由系统有以上五种,所有的路由系统都是基于以下对应关系来处理:
    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }

    反向生成带参数的URL,怎么做呢?

    @app.route("/index/<int:id>")
    def index(id):
        print(url_for("index", id=id))  # id=1 生成固定参数的url
        return "index"

    CBV

    from flask import Flask, views, url_for
    
    app = Flask(__name__)
    
    def auth(func):
        @wraps(func)
        def inner(*args, **kwargs):
            print('before')
            result = func(*args, **kwargs)
            print('after')
            return result
    return inner
    
    class IndexView(views.View):
        methods = ['GET']
        decorators = [auth, ]
    
        def dispatch_request(self):
            print('Index')
            return 'Index'
    
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    
    #
    
    class IndexView(views.MethodView):
        methods = ['GET']
        decorators = [auth, ]
    
        def get(self):
            return 'Index.GET'
    
        def post(self):
            return 'Index.POST'
    
    app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name=endpoint
    View Code

    @app.route和app.add_url_rule参数

    rule                    # URL规则
    view_func               # 视图函数名称
    defaults=None           # 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
    endpoint=None           # 名称,用于反向生成URL,即: url_for('名称')
    methods=None            # 允许的请求方式,如:["GET", "POST"]
    
    strict_slashes=None     # 对URL最后的 / 符号是否严格要求,
                            # 如:
                            @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
    
    redirect_to=None,       # 重定向到指定地址
                            # 如:
                            @app.route('/index/<int:id>', redirect_to='/home/<id>')
                            或
                            def func(adapter, id):
                                return "/home/888"
                            @app.route('/index/<int:nid>', redirect_to=func)
    
    subdomain=None,         # 子域名访问
                            from flask import Flask, views, url_for
    
                            app = Flask(import_name=__name__)
                            app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
    
                            @app.route("/", subdomain="admin")
                            def static_index():
                                """Flask supports static subdomains
                                This is available at static.your-domain.tld"""
                                return "static.your-domain.tld"
    
                            @app.route("/dynamic", subdomain="<username>")
                            def username_index(username):
                                """Dynamic subdomains are also supported
                                Try going to user1.your-domain.tld/dynamic"""
                                return username + ".your-domain.tld"
    
                            if __name__ == '__main__':
                                app.run()
    View Code

    自定制正则路由匹配

    from flask import Flask, url_for
    from werkzeug.routing import BaseConverter
    
    app = Flask(import_name=__name__)
    
    
    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
    
    
    # 添加到flask中
    app.url_map.converters["regex"] = RegexConverter
    
    
    @app.route("/index/<regex('d+'):id>")
    def index(id):
        return url_for("index", id=id)
    
    
    if __name__ == "__main__":
        app.run()
    View Code

    四、请求和响应

    from flask import Flask
    from flask import request
    from flask import render_template
    from flask import redirect
    from flask import make_response
    from flask import jsonify
    import os
    
    app = Flask(__name__)
    
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    
    @app.route("/login", methods=["GET", "POST"])
    def login():
        # 请求相关信息
        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.get("the_file_name")  # 拿到上传的文件名
        obj.save(os.path.join(BASE_DIR, "files", obj.filename))  # 保存到本地路径
    
        # 响应相关信息(响应体)
        return "字符串"
        data = {"key": "val"}
        return jsonify(data)  # 相当于 json.dumps(data)
        return render_template("login.html", **{})
        return redirect("/index")
        # 设置响应头
        response = make_response(render_template("index.html"))  # 将响应内容封装到这个对象中,再设置
        # response是flask.wrappers.Response类型
        response.delete_cookie("key")
        response.set_cookie("key", "val")
        response.headers["key"] = "val"
        return response
    
    if __name__ == "__main__":
        app.run()
    View Code

    五、Session

    session 对象,允许在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,需要设置一个密钥。

    设置:session["user"] = "xx"
    获取:session.get("user")
       session["user"] 删除:session.pop(
    "user", None) # 可以在settings中设置秘钥 class DevelopmentConfig(Config): DEBUG = True SECRET_KEY = "asdf"

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

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

    第三方session

    """
    pip3 install redis
    pip3 install flask-session
    """
    
    import redis
    from flask import Flask, session
    from flask_session import Session
    # from flask.ext.session import Session  # 老版本,同 from flask_session import Session
    
    app = Flask(__name__)
    
    app.config["SESSION_TYPE"] = "redis"
    app.config["SESSION_REDIS"] = redis.Redis(host="127.0.0.1",port=6379)
    Session(app)
    
    @app.route("/login")
    def login():
        session["user"] = "username"
        return "login"
    
    @app.route("/index")
    def index():
        print(session.get("user"))
        return "index"
    
    if __name__ == "__main__":
        app.run()
    View Code

    flash

    临时存储数据,取了就没了;在session中存储一个数据,读取时通过pop将数据移除。

    from flask import Flask, flash, get_flashed_messages
    
    app = Flask(__name__)
    
    @app.route('/test1')
    def test1():
        flash('aa', 'error')  # 第二个参数:分类
        flash('bb', 'error')
        flash('cc', 'info')
        return "Set Session"
    
    @app.route('/test2')
    def test2():
        print(get_flashed_messages(category_filter=['error']))  # ['aaaaa', 'bbbbb']
        return "Get Session"
    
    if __name__ == "__main__":
        app.run()
    View Code

    六、模板

    1、Flask 使用的是 Jinja2 模板,所以其语法和 Django 无差别。

    {% for k,v in data.items() %}
    <tr>
        <td>{{ k }}</td>
        <td>{{ v.name }}</td>
        <td>{{ v["age"] }}</td>
        <td>{{ v.get("hobby", "默认") }}</td>
    </tr>
    {% endfor %}
    @app.route("/test")
    def test():
        txt1 = Markup("<h1>哈哈</h1>")  # Markup相当于Django的mark_safe
        txt2 = "<h1>呵呵</h1>"
        return render_template("test.html", **{"txt1": txt1, "txt2": txt2})
    #######################################################################
    {{ txt1 }}
    {{ txt2|safe }}
    @app.template_global()
    def func1(a1, a2):
        return a1+a2
    
    @app.template_filter()
    def func2(a1, a2, a3):
        return a1+a2+a3
    
    # 调用方式,模板中:{{ func1(1,2) }}  {{ 1|func2(2,3) }}

    2、自定义模板方法

    from flask import Flask, render_template
    
    app = Flask(__name__)
    
    def func():
        return '<h1>哈哈哈</h1>'
    
    @app.route('/test')
    def test():
        return render_template('test.html', xx=func)
    
    if __name__ == "__main__":
        app.run()
    ################################################
    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>自定义函数</h1>
        {{ xx()|safe }}
    </body>
    </html>
    View Code

    macro

    <!DOCTYPE html>
    <html lang="zh-cn">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {# 定义 #}
    {% macro func(name, type='text', value='') %}
        <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
    {# 执行 #}
    {{ func('password', type='password', value=123456) }}
    </body>
    </html>
    View Code

    七、特殊装饰器

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.before_first_request
    def before_first_request1():
        print('before_first_request1')
    
    @app.before_first_request
    def before_first_request2():
        print('before_first_request2')
    
    @app.before_request
    def before_request1():
        print('before_request1')
    
    @app.before_request
    def before_request2():
        print('before_request2')
    
    @app.after_request
    def after_request1(response):
        print('after_request1', response)
        return response
    
    @app.after_request
    def after_request2(response):
        print('after_request2', response)
        return response
    
    @app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        app.run()
    
    # before_first_request1
    # before_first_request2
    # before_request1
    # before_request2
    # after_request2 <Response 5 bytes [200 OK]>
    # after_request1 <Response 5 bytes [200 OK]>
    
    ############################################
    
    # 比较少的函数中需要额外添加功能,使用装饰器
    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 'index'
        
    # 给全局加上登录验证
    @app.before_request
    def before_request():
        if request.path == "/login":
            return None
        if session.get("user"):
            return None
        return redirect("login")
    
    ############################################
    
    @app.errorhandler(404)
    def page_not_found(error):
        return '页面不见了'
    View Code

    八、蓝图

    蓝图用于为应用提供目录划分。

    小中型:

    account.py

    from flask import Blueprint
    from flask import render_template
    
    account = Blueprint("account", __name__)
    
    @account.route("/login", methods=["GET", "POST"])
    def login():
        return render_template("login.html")

    course.py

    from flask import Blueprint
    
    course = Blueprint("course", __name__)

    __init__.py

    from flask import Flask
    from .views.account import account
    from .views.course import course
    
    app = Flask(__name__, template_folder="templates", static_folder="statics", static_url_path="/static")
    
    app.register_blueprint(account)
    app.register_blueprint(course)

    run.py

    from pro_flask import app
    
    if __name__ == "__main__":
        app.run()

    大型:

    admin / __init__.py

    from flask import Blueprint
    
    admin = Blueprint(
        "admin",
        __name__,
        template_folder="templates",
        static_folder="static"
    )
    from . import views

    admin / views.py

    from . import admin
    
    @admin.route("/index")
    def index():
        return "Admin.Index"

    blog / __init__.py

    from flask import Blueprint
    
    blog = Blueprint(
        "blog",
        __name__,
        template_folder="templates",
        static_folder="static"
    )
    from . import view

    blog / views.py

    from . import blog
    
    @blog.route("/index")
    def index():
        return "Blog.Index"

    pro_flask / __init__.py

    from flask import Flask
    from .admin import admin
    from .blog import blog
    
    app = Flask(__name__)
    app.debug = True
    
    app.register_blueprint(admin, url_prefix="/api")  # url前缀
    app.register_blueprint(blog)

    run.py

    from pro_flask import app
    
    if __name__ == "__main__":
        app.run()

    url_prefix参数的作用:

    http://127.0.0.1:5000/index      # Blog.Index
    http://127.0.0.1:5000/api/index  # Admin.Index

    小中型应用程序目录:查看

    大型应用程序目录:查看

    九、Flask插件

    http://flask.pocoo.org/extensions/

  • 相关阅读:
    视频聊天相关技术介绍
    block相关归纳
    block的作用
    block教程
    向appstore提交app流程
    ios xmpp 发送语音图片解决方案
    python 三元运算、列表推倒式、字典推倒式、生成器生成式
    python 生成器
    python 迭代器(第二次总结)
    python 迭代器
  • 原文地址:https://www.cnblogs.com/believepd/p/10295168.html
Copyright © 2020-2023  润新知