• Flask 基础


    Falsk

    Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions.

    “微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。

    默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。

    Start Flask

    pip insatll flask

    werkzeug 简单应用

    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) # 开启本地 监听4000端口,绑定函数
    

    Flask 简单应用

    1.简单应用
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask
    app = Flask(__name__)
    
    app.debug = True
    @app.route("/")
    def sayhello():
    
        return "hello word"
    
    if __name__ == '__main__':
        app.run()
    

    2.配置文件系统

    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,
        }
     
    方式一:
        app.config['DEBUG'] = True
     
        PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)
     
    方式二:
        app.config.from_pyfile("python文件名称")
            如:
                settings.py
                    DEBUG = True
     
                app.config.from_pyfile("settings.py")
     
        app.config.from_envvar("环境变量名称")
            环境变量的值为python文件名称名称,内部调用from_pyfile方法
     
     
        app.config.from_json("json文件名称")
            JSON文件名称,必须是json格式,因为内部会执行json.loads
     
        app.config.from_mapping({'DEBUG':True})
            字典格式
     
     
     
     
     
        app.config.from_object("python类或类的路径") # 主要的应用模式
     
            app.config.from_object('pro_flask.settings.TestingConfig')
     
            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
     
            PS: 从sys.path中已经存在路径开始写
         
     
        PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录
    
    
    3.路由系统
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    
    # 路由系统 函数 视图
    from flask import Flask
    app = Flask(__name__)
    app.debug = True
    
    # 源码实例 router() 装饰器的原理 
    """
    def route(self, rule, **options):
      def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator      
    """
    @app.route("/index")
    def sayhello():
        return "hello word"
    def login():
        return "login"
    app.add_url_rule("/", "n2", login, methods=["GET", "POST"] )
    
    if __name__ == '__main__':
        
        app.run()
    
    # 路由系统支持的 匹配模式
    @app.route('/user/<username>')
    @app.route('/post/<int:post_id>')
    @app.route('/post/<float:post_id>')
    @app.route('/post/<path:path>')
    @app.route('/login', methods=['GET', 'POST'])
    常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理:
    
    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }
    
    
    3.1 其次我们也可以自己注册自己的规则
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask
    from werkzeug.routing import BaseConverter
    app = Flask(__name__)
    
    # 自定制正则路由匹配
    
    class RegexConverter(BaseConverter):
    
        def __init__(self, map, regex):
            super(RegexConverter, self).__init__(map)
            self.regex = regex
    
        def to_python(self, value):
            """
            这里面对匹配到的字符串就行加工
            :param value:
            :return:
            """
            return value
    
        def to_url(self, value):
            """
            反向生成url的时候需要用到
            :param value:
            :return:
            """
            val = super(RegexConverter, self).to_python(value)
            return val
    
    
    app.debug = True
    
    app.url_map.converters["regex"] = RegexConverter # 注册自己自己的url路有关系
    
    
    @app.route("/")
    def sayhello():
        return "hello word"
    
    
    @app.route("/index/<regex('xbd+'):nid>", methods=["GET"])
    def index(nid):
        print(nid)
        return "index"
    
    if __name__ == '__main__':
        app.run()
    
     @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:nid>', redirect_to='/home/<nid>')
                                                或
                                                def func(adapter, nid):
                                                    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"
    
    4.CBV 模式的分发规则
    
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    
    # 类视图的路由
    
    from flask import Flask, views
    
    app = Flask(__name__)
    app.debug = True
    
    
    def auth(func):
        def inner(*args, **kwargs):
            return func(*args, **kwargs)
    
        return inner
    
    
    class IndexView(views.MethodView):
        methods = ["GET", ] method 的list
        decorators = [auth, ] # 装饰器的list
    
        def get(self):
            return "index.get"
    
        def post(self):
            return "index.get"
    
    # 注册路由规则,加类  name 是 反向的url 名称
    app.add_url_rule('/index', view_func=IndexView.as_view(name="index"))
    
    if __name__ == '__main__':
        app.run()
    
    5.模板语言

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

    2、自定义模板方法
    Flask中自定义模板方法的方式和Bottle相似,创建一个函数并通过参数的形式传入render_template

    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask, render_template, Markup, jsonify, make_response
    
    app = Flask(__name__)
    app.debug = True
    
    
    def func(n):
        return n + "sssss" # 自定义函数
        
        
    def input(s):
        text = "<input type='text' value=%s />" % s # 自定义input标签,用makeup来保证安全性
        text = Markup(text)
        return text
    
    @app.route("/")
    def sayhello():
        return render_template("s7.html", **{"func": func, "input": input})
    if __name__ == '__main__':
        app.run(port=8001)
    
    注意:Markup等价django的mark_safe
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <!--支持函数的使用-->
    <h2>{{func("www")}}</h2>
    
    {{input("11")}}
    
    
    {{input("11")|safe}} # 也可以这样 如果后端不做makeup的时候 这样也说明是安全的
    
    
    <!-- 宏定义 类似函数-->
    {% macro input(name, type='text', value='') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
    {% endmacro %}
    
    {{ input('n1') }}
    
    </body>
    </html>
    
    5.1自定义模板语言
    @app.template_global()
    def sb(a1, a2):
        return a1 + a2
    
    
    @app.template_filter() 
    def db(a1, a2, a3):
        return a1 + a2 + a3
    
    使用:
    {{sb(1,2)}}  {{ 1|db(2,3)}}
    
    
    5.2 cookies的设定
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask, render_template, Markup, jsonify, make_response
    
    app = Flask(__name__)
    app.debug = True
    
    @app.route("/", methods=["GET"])
    def index():
    
        # text = "cookies"
        # text = make_response(text)
        # text.set_cookie("XXXX") #设置cookies
        html = render_template("s7.html",text="1111")
        response = make_response(html) 
        response.headers["xxx"] = "xxxx" # 设置headers
        return response
    if __name__ == '__main__':
        app.run(port=8001)
    
    

    6.请求相应相关参数

    from flask import Flask
        from flask import request
        from flask import render_template
        from flask import redirect
        from flask import make_response
    
        app = Flask(__name__)
    
    
        @app.route('/login.html', 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['the_file_name'] # 获取文件obj存储
            # obj.save('/var/www/uploads/' + secure_filename(f.filename))
    
            # 响应相关信息
            # return "字符串"
            # return render_template('html模板路径',**{})
            # return redirect('/index.html')
            
            # 对响应进行包装
            
            # response = make_response(render_template('index.html'))
            # response是flask.wrappers.Response类型
            # response.delete_cookie('key')
            # response.set_cookie('key', 'value')
            # response.headers['X-Something'] = 'A value'
            # return response
    
            return "string"
    
        if __name__ == '__main__':
            app.run()
    
    6.1 Session相关

    基本使用(lower)

    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask, render_template, request, redirect, session, url_for
    
    app = Flask(__name__)
    app.debug = True
    
    
    # app.config["SECRET_KEY"] = "1234"
    app.secret_key = "123" # 开头需要加盐 这样才不会报错 两种形式
    
    
    USERS = {
        1: {'name': '老王', 'age': 18, 'gender': '男',
            'text': "当眼泪掉下来的时候,是真的累了, 其实人生就是这样: 你有你的烦,我有我的难,人人都有无声的泪,人人都有难言的苦。 忘不了的昨天,忙不完的今天,想不到的明天,走不完的人生,过不完的坎坷,越不过的无奈,听不完的谎言,看不透的人心放不下的牵挂,经历不完的酸甜苦辣,这就是人生,这就是生活。"},
        2: {'name': '老李', 'age': 28, 'gender': '男',
            'text': "高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
        3: {'name': '老鸨', 'age': 18, 'gender': '女',
            'text': "高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
    }
    
    import functools
    
    # 装饰器的使用,每次来验证session 
    
    
    # 因为有一点需要明确 就是 endpoint 不指定默认 用函数名
    # 导致我们加装饰器的时候 每次返回的inners函数的名字不能一样 需要改成 传入的 func函数的名字
    
    
    def verfriy(func):
        @functools.wraps(func) # 函数属性转移
        def inners(*args, **kwargs):
            user = session.get("user_info")
            if not user:
                url = url_for("login")
                return redirect(url)
            return func(*args, **kwargs)
    
        # inners.__name__ = func.__name__ # 也可以这样做 
    
        return inners
    
    
    @app.route("/", methods=["GET", "POST"], endpoint="login")
    def login():
        if request.method == "GET":
            return render_template("login.html", )
        else:
            user = request.form.get("user")
            pwd = request.form.get("pwd")
    
            if user == "alex" and pwd == "123":
                session["user_info"] = user
                return redirect("/index")
            else:
                return render_template("login.html", **{"msg": "erro"})
    
    
    @app.route("/index", methods=["GET"])
    @verfriy
    def index():
        return render_template("index.html", user_dict=USERS)
    
    
    @app.route("/detail/<int:nid>", methods=["GET"])
    @verfriy
    def detail(nid):
        user_info = USERS.get(nid)
        return render_template("detail.html", user_info=user_info)
    
    
    if __name__ == '__main__':
        app.run(port=5001)
    
    
    后续会添加自定义seesion
    7. Flask 中的 蓝图

    小型的目录结构:

    蓝图

    
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    
    from flask import Blueprint, render_template 
    
    # 各个蓝图 view 里面的code
    
    account = Blueprint("account", __name__, template_folder="templates",url_prefix="/account") 
    # 可重新 定义templates的文件夹,并且可以设置url的分组前缀(重要)
    
    
    @account.route("/")
    
    def index():
    
        return render_template("actest.html")
    
    

    大型的目录结构:
    大型蓝图

    各个文件夹下的__init__方法的code

    
    # -*- coding:utf-8 -*-
    
    from flask import Blueprint
    
    admin = Blueprint(
        'admin',
        __name__,
        template_folder='templates',
        static_folder='static'
    )
    from . import views # 视图函数 
    
    

    各个文件夹下的view 函数文件

    # -*- coding:utf-8 -*-
    
    from . import admin
    
    
    @admin.route('/index')
    def index():
        return 'Admin.Index'
    
    
    8. flash (message) 闪现

    message是一个基于Session实现的用于保存数据的集合,其特点是:使用一次就删除。

    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask, flash, get_flashed_messages, request, redirect
    
    app = Flask(__name__)
    app.debug = True
    app.secret_key = "1111"
    
    
    @app.route("/")
    def index():
        val = request.get_data("page")
    
        if val == 'page':
            return "page"
    
    
        else:
            flash("page not get !", category="erro") # 向flash中添加 messgae ,可以指定 category的类型,以便获取
    
            return redirect("/erro")
    
    
    @app.route("/erro")
    def erro():
    
        eval = get_flashed_messages(category_filter="erro")  
        # 是一个 列表的形式  取category 放进去的值
        
        print(eval)
    
        return "错误信息:" + eval[0]
    
    
    if __name__ == '__main__':
        app.__call__()
        app.run()
    
    
    9.中间件
    9.1 基于flask 装饰器的中间件

    before_request after_request

    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask, render_template, request, redirect, session, url_for
    
    app = Flask(__name__)
    app.debug = True
    app.secret_key = "123"
    # 请求到来之前做session验证,不需要使用装饰器
    # 请求扩展
    
    USERS = {
        1: {'name': '老张', 'age': 18, 'gender': '男',
            'text': "当眼泪掉下来的时候,是真的累了, 其实人生就是这样: 你有你的烦,我有我的难,人人都有无声的泪,人人都有难言的苦。 忘不了的昨天,忙不完的今天,想不到的明天,走不完的人生,过不完的坎坷,越不过的无奈,听不完的谎言,看不透的人心放不下的牵挂,经历不完的酸甜苦辣,这就是人生,这就是生活。"},
        2: {'name': '狼王', 'age': 28, 'gender': '男',
            'text': "高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
        3: {'name': '老鸨', 'age': 18, 'gender': '女',
            'text': "高中的时候有一个同学家里穷,每顿饭都是膜膜加点水,有时候吃点咸菜,我们六科老师每天下课都叫他去办公室回答问题背诵课文,然后说太晚啦一起吃个饭,后来他考上了人大,拿到通知书的时候给每个老师磕了一个头"},
    }
    
    # 每次请求到来之前 执行before_request 装饰器函数,实现session的验证
    @app.before_request 
    def process_request(*args,**kwargs):
        print(request.path)
        if request.path == '/':
            return  # 返回none 证明 可以执行 下面的request
        user = session.get("user_info")
        print(user)
        if user:
            return
        return redirect("/")  # 返回相对应的地址
    
    
    @app.before_request
    def process_request1(*args, **kwargs):
        print("process_request1")
    
    
    @app.before_request
    def process_request2(*args, **kwargs):
        print("process_request2")
    
    
    @app.route("/", methods=["GET", "POST"], endpoint="login")
    def login():
        if request.method == "GET":
            return render_template("login.html", )
        else:
            user = request.form.get("user")
            pwd = request.form.get("pwd")
    
            if user == "alex" and pwd == "123":
                session["user_info"] = user
                return redirect("/index")
            else:
                return render_template("login.html", **{"msg": "erro"})
    
    
    @app.route("/index", methods=["GET"])
    def index():
        return render_template("index.html", user_dict=USERS)
    
    
    @app.route("/detail/<int:nid>", methods=["GET"])
    def detail(nid):
        user_info = USERS.get(nid)
        return render_template("detail.html", user_info=user_info)
    
    
    @app.after_request
    def process_response1(response, *args, **kwargs):
        print("process_response1")
        return response
    
    
    @app.after_request
    def process_response2(response, *args, **kwargs):
        print("process_response2")
        return response
    
    
    # before_request返回none时 执行下一个request 否则拦截 但是还是会执行response函数
    # 执行顺序 request1 -> request2 -> response2 -> response1
    
    
    
    
    
    @app.errorhandler(404)   # 定制错误信息
    def erro_404(arg):
        return "404"
    
    
    if __name__ == '__main__':
        app.run(port=5002)
        
        
    
    9.2中间件的 自定制
    # _*_ coding:utf-8 _*_
    # __author__Zj__
    from flask import Flask
    
    app = Flask(__name__)
    app.debug = True
    # 自定义中间件
    
    @app.route("/")
    def sayhello():
        return "hello word"
        
    class Md(object):
    
        def __init__(self, old_wsgi_app):
            self.old_wsgi_app = old_wsgi_app
    
        def __call__(self, environ, start_response):
            # 实例化的时候运行call 方法
            print("before")
            ret = self.old_wsgi_app(environ, start_response)
            print("after")
            return ret
    if __name__ == '__main__':
        # 这一步 是进行实例化把  
        Flask——>app.wsgi_app
        传递进来,接着就执行call方法 其实就是执行app.wsgi_app(参数)
        app.wsgi_app = Md(app.wsgi_app)  # 执行 Md  __call__ 方法
    
        app.run(port=9000)
        
    

    app 的 call 方法源码

    def wsgi_app(self, environ, start_response):
          
            ctx = self.request_context(environ)  # requestCountext
            ...........
    
    def __call__(self, environ, start_response):
            return self.wsgi_app(environ, start_response)
            
    
  • 相关阅读:
    mysql代码实现hive中的rank()排序方法,获得top3中的最小值
    MySQL--Hive中字段数据类型对比
    使用shell脚本连接mysql shell脚本执行mysql语句
    WPS中查看超链接后返回超链接位置
    shell脚本中常用的命令
    Lamda一行代码实现"36选7"随机自动选号
    创建Visual studio项目模板 vstemplate关键点纪要
    网络传输及数据解析
    动画
    触摸事件与手势识别
  • 原文地址:https://www.cnblogs.com/zjcode/p/9129187.html
Copyright © 2020-2023  润新知