zoukankan      html  css  js  c++  java
  • Flask

    一、Flask简介

    Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

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

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

    安装

    pip3 install flask
    from flask import Flask, render_template, redirect, request, session, url_for, jsonify
    
    app = Flask(__name__)  # 生成一个flask对象,传入当前文件的名字
    # 一旦用session,一定记住,要写secret_key
    app.secret_key = 'jiayan'
    USER_LIST = {
        1: {'name': '张三', 'age': 18, 'text': '道路千万条'},
        2: {'name': '李四', 'age': 28, 'text': '安全第一条'},
        3: {'name': '王五', 'age': 38, 'text': '行车不规范'}
    }
    
    # 伪装装饰器wraps
    from functools import wraps
    
    
    # 登录装饰器
    def login_auth(func):
        @wraps(func)  # 伪装函数名为被装饰函数名:如果不做伪装,就会报错
        def inner(*args, **kwargs):
            if session.get('user'):
                res = func(*args, **kwargs)
                return res
            else:
                return redirect('/login')
    
        return inner
    
    
    # 路由和视图的映射关系
    @app.route('/')
    def index():
        url = url_for('login')  # 反向解析
        print(url)
        return render_template('test1.html', test1=test1)
    
    
    @app.route('/login', methods=['POST', 'GET'], endpoint='login')
    def login():
        '''
        返回页面:对照Django
        httpresponse ------>  ''
        render ------>  render_template
        redirect -----> redirect
        '''
        if request.method == 'GET':
            return render_template('login.html')
        else:
            name = request.form.get('name')
            pwd = request.form.get('pwd')
            if name == 'mogu' and pwd == '123':
                session['user'] = name
                return redirect('/user_list')
            else:
                return render_template('login.html', error='用户名密码错误')
    
    
    @app.route('/user_list', methods=['GET'])
    @login_auth
    def user_list():
        return render_template('use_list.html', user_list=USER_LIST)
    
    
    @app.route('/userdetail/<int:nid>', methods=['GET'])
    @login_auth
    def userdetail(nid):
        print(nid)
        msg = USER_LIST.get(nid)
        return render_template('userdetail.html', msg=msg)
    
    
    def test1(x, y):
        l1 = {}
        for i in range(10):
            l1[i] = x * y
        return l1
    
    
    app.debug = True
    if __name__ == '__main__':
        app.run()
    flask快速搭建
    #login.html
    <form action="" method="post">
        <p>用户名:<label><input type="text" name="name"></label></p>
        <p>密 码:<input type="text" name="pwd"></p>
        <input type="submit" value="提交"><span>{{error}}</span>
    </form>
    
    #user_list.html
    <table border="1px">
      <thead>
      <tr>
        <th>id</th>
        <th>姓名</th>
        <th>详细</th>
      </tr>
      </thead>
      <tbody>
      {% for k,v in user_list.items() %}
          <tr>
              <td>{{ k }}</td>
              <td>{{ v.name }}</td>
              <!--<td>{{ v['name'] }}</td>-->
              <!--<td>{{ v.get('name') }}</td>-->
              <td><a href="/userdetail/{{ k }}">详细信息</a></td>
          </tr>
      {% endfor %}
      </tbody>
    </table>
    
    #userdetail.html
    <p>{{ msg.name }}</p>
    <p>{{ msg.age }}</p>
    <p>{{ msg.text }}</p>
    
    #test1.html
    {{ test1(3,4) }}
    html页面

    ps:

      多个装饰器执行顺序

      反向查找的名称(endpoint),不允许重复

    二、配置文件

    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(...)

    方式二

    #通过py文件配置
    app.config.from_pyfile("python文件名称")
    如:
    settings.py
    DEBUG = True
    
    app.config.from_pyfile("settings.py")
    #通过环境变量配置
    app.config.from_envvar("环境变量名称")
    #app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
    环境变量的值为python文件名称名称,内部调用from_pyfile方法
    #通过json配置
    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目录(Flask对象init方法的参数)

    三、路由

    @app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')

    转换器

    DEFAULT_CONVERTERS = {
        'default':          UnicodeConverter,
        'string':           UnicodeConverter,
        'any':              AnyConverter,
        'path':             PathConverter,
        'int':              IntegerConverter,
        'float':            FloatConverter,
        'uuid':             UUIDConverter,
    }
    """
    1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')
        def route(self, rule, **options):
            # app对象
            # rule= /
            # options = {methods=['GET','POST'],endpoint='n1'}
            def decorator(f):
                endpoint = options.pop('endpoint', None)
                self.add_url_rule(rule, endpoint, f, **options)
                return f
            return decorator
    2. @decorator
        decorator(index)
    """
    #同理
    def login():
        return '登录'
    app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"])
    #与django路由类似
    #django与flask路由:flask路由基于装饰器,本质是基于:add_url_rule
    #add_url_rule 源码中,endpoint如果为空,endpoint = _endpoint_from_view_func(view_func),最终取view_func.__name__(函数名)
    路由本质

    CBV

    def auth(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

    app.add_url_rule参数

    @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"]
    #对URL最后的 / 符号是否严格要求
    strict_slashes = None
        '''
            @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>')
        '''
    #1 写类,继承BaseConverter
    #2 注册:app.url_map.converters['regex'] = RegexConverter
    # 3 使用:@app.route('/index/<regex("d+"):nid>')  正则表达式会当作第二个参数传递到类中
    from flask import Flask, views, 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):
            """
            路由匹配时,匹配成功后传递给视图函数中参数的值
            """
            return int(value)
    
        def to_url(self, value):
            """
            使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
            """
            val = super(RegexConverter, self).to_url(value)
            return val
    # 添加到flask中
    app.url_map.converters['regex'] = RegexConverter
    @app.route('/index/<regex("d+"):nid>')
    def index(nid):
        print(url_for('index', nid='888'))
        return 'Index'
    
    if __name__ == '__main__':
        app.run()
    正则写法

    四、模板(jinja2)

    比django中多可以加括号,执行函数,传参数

    from flask import Flask,render_template,Markup,jsonify,make_response
    app = Flask(__name__)
    
    def func1(arg):
        return Markup("<input type='text' value='%s' />" %(arg,))
    @app.route('/')
    def index():
        return render_template('index.html',ff = func1)
    
    if __name__ == '__main__':
        app.run()
    View Code

     url:点我

    ps:

    1.Markup等价django的mark_safe ,

    2.extends,include一模一样

    五、请求响应

        from flask import Flask,request,render_template,redirect,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.save('/var/www/uploads/' + secure_filename(f.filename))
    
            # 响应相关信息
            # return "字符串"
            # return render_template('html模板路径',**{})
            # return redirect('/index.html')
            # return jsonify({'k1':'v1'})
            # 如果加cookie,往响应头中写东西
            # 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 "内容"
    
        if __name__ == '__main__':
            app.run()

    六、session

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

    设置:session['username'] = 'xxx'
    删除:session.pop('username', None)
         del session['username']

    七、闪现(message)

    -设置: flash('aaa')
    -取值:get_flashed_message()
    -假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
    from flask import Flask,flash,get_flashed_messages,request,redirect
    
    app = Flask(__name__)
    app.secret_key = 'asdfasdf'
    
    
    @app.route('/index')
    def index():
        # 从某个地方获取设置过的所有值,并清除。
        val = request.args.get('v')
        if val == 'oldboy':
            return 'Hello World!'
        flash('超时错误',category="x1")
        return "ssdsdsdfsd"
        # return redirect('/error')
    
    
    @app.route('/error')
    def error():
        """
        展示错误信息
        :return:
        """
        data = get_flashed_messages(category_filter=['x1'])
        if data:
            msg = data[0]
        else:
            msg = "..."
        return "错误信息:%s" %(msg,)
    
    if __name__ == '__main__':
        app.run()
    示例

    八、请求扩展

    before_request

    类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情

    #基于它做用户登录认证
    @app.before_request
    def process_request(*args,**kwargs):
        if request.path == '/login':
            return None
        user = session.get('user_info')
        if user:
            return None
        return redirect('/login')

    after_request

    类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常

    @app.after_request
    def process_response1(response):
        print('process_response 走了')
        return response

    before_request

    第一次请求时,跟浏览器无关

    @app.before_first_request
    def first():
        print('我的第一次')
  • 相关阅读:
    【Mysql 8001错误
    【mysql查询今天、昨天、7天、近30天、本月、上一月 数据】
    bootstrap-table 常用总结-1
    前端下载图片
    swiper 轮播中常用的效果,持续更新
    常用的时间函数整理
    拼接字符转的转义
    Ajax跨域请求,设置content
    JS MD5 返回二进制格式
    jqgrid three 树形结构
  • 原文地址:https://www.cnblogs.com/nixindecat/p/10886458.html
Copyright © 2011-2022 走看看