zoukankan      html  css  js  c++  java
  • 初识Flask

    Flask介绍

    flask是一个短小精悍、可扩展性强的一个Web框架。

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

    werkzeug

    werkzeug是实现WSGI的一个模块

    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)
    werkzeug

    Flask简单使用

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

    配置文件

    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.from_object("settings.DevelopmentConfig")
            
            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
    import_name,
            static_url_path=None,   设置静态文件url
            static_folder='static',     默认静态文件路径
            static_host=None,
            host_matching=False,
            subdomain_matching=False,
            template_folder='templates',  默认模板路劲
            instance_path=None,
            instance_relative_config=False,
            root_path=None

    路由系统

    • @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'])

    路由系统参数:

    @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"
    
    
                                            if __name__ == '__main__':
                                                app.run()

    反向生成url

    - endpoint,反向生成URL,默认函数名
    @app.route('/index/',methods=['GET'],endpoint='n1')
    def hello():
           url=url_for('n1') 
    
    #没有定义endpoint
           url=url_for('hello')
    
            - 动态路由:
                @app.route('/index/<int:nid>',methods=['GET','POST'])
                def index(nid):
                    print(nid)
          #动态路由反向生成:url_for("index",nid=777)
    
                    return "Index"    

    路由系统的使用:

    FBV

    def auth(func):
        def inner(*args, **kwargs):
            print('before')
            result = func(*args, **kwargs)
            print('after')
            return result
        return inner
        
    
    @app.route('/index.html',methods=['GET','POST'],endpoint='index')
    @auth
    def index():
        return 'Index'def index():
        return "Index"
    
    self.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
    or
    app.add_url_rule(rule='/index.html', endpoint="index", view_func=index, methods=["GET","POST"])
    app.view_functions['index'] = index

    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

    自定义正则

    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):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        :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
    
    # 步骤二:添加到转换器
    app.url_map.converters['reg'] = RegexConverter
    
    """
    1. 用户发送请求
    2. flask内部进行正则匹配
    3. 调用to_python(正则匹配的结果)方法
    4. to_python方法的返回值会交给视图函数的参数
    
    """
    
    # 步骤三:使用自定义正则
    @app.route('/index/<reg("d+"):nid>')
    def index(nid):
        print(nid,type(nid))
    
        print(url_for('index',nid=987))
        return "index"
    
    if __name__ == '__main__':
        app.run()

    请求

       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         获取get方法的参数
            # request.form        获取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 "内容"
    
        if __name__ == '__main__':
            app.run()    

     响应

            # 响应相关信息
            return "字符串"
            return render_template('html模板路径',**{})
             return redirect('/index')
    
           #自定制响应头
            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

    模板

    基本数据类型

    基本数据类型:可以执行python语法,如:

    #字典
                    {{values.get('name')}}
                    {{values['name']}}
                    #列表
                    {{values[0]}}
                    #函数
                    {{func(可传参数)}}
                    #循环
                    {%for item in xxx%}
                    {%endfor%}
            传入函数
                - django,自动执行
                - flask,不自动执行

    全局定义函数

    @app.template_global()
        def sb(a1, a2):
            # {{sb(1,9)}}
            return a1 + a2
    
    @app.template_filter()
        def db(a1, a2, a3):
            # {{ 1|db(2,3) }}
            return a1 + a2 + a3

    模板(继承、块、安全、宏定义)

    继承和块

    - 模板继承
                layout.html
                    <!DOCTYPE html>
                    <html lang="zh-CN">
                    <head>
                        <meta charset="UTF-8">
                        <title>Title</title>
                        <meta name="viewport" content="width=device-width, initial-scale=1">
                    </head>
                    <body>
                        <h1>模板</h1>
                        {% block content %}{% endblock %}
                    </body>
                    </html>
                
                tpl.html
                    {% extends "layout.html"%}
                    {% block content %}
                        {{users.0}}
                    {% endblock %}    

    include

    include 
                {% include "form.html" %}
                form.html 
                    <form>
                        asdfasdf
                        asdfasdf
                        asdf
                        asdf
                    </form>

    宏定义

    相当于定义了一个函数,

    在全局都可以调用

    {% macro ccccc(name, type='text', value='') %}
                    <h1>宏</h1>
                    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
                    <input type="submit" value="提交">
                {% endmacro %}
    
                {{ ccccc('n1') }}
    
                {{ ccccc('n2') }}

    安全

    安全
                - 前端: {{u|safe}}
                - 后端: MarkUp("<a></a>")

    Session

    当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,

    将该值解密并反序列化成字典,放入内存以便视图函数使用。

    视图函数:
        @app.route('/ses')
        def ses():
            session['k1'] = 123
            session['k2'] = 456
            del session['k1']
    
            return "Session"
                session['xxx'] = 123

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

    闪现

    闪现,在session中存储一个数据,读取时通过pop将数据移除。

    from flask import Flask,flash,get_flashed_messages
    @app.route('/page1')
    def page1():
        flash('临时数据存储','error')
        flash('sdfsdf234234','error')
        flash('adasdfasdf','info')
        return "Session"
    @app.route('/page2')
    def page2():
        print(get_flashed_messages(category_filter=['error']))
        return "Session"

    中间件

    call方法什么时候出发?
        - 用户发起请求时,才执行。
    任务:在执行call方法之前,做一个操作,call方法执行之后做一个操作。
        class Middleware(object):
            def __init__(self,old):
                self.old = old
    
            def __call__(self, *args, **kwargs):
                ret = self.old(*args, **kwargs)
                return ret
    
    
        if __name__ == '__main__':
            app.wsgi_app = Middleware(app.wsgi_app)
            app.run()

    特殊装饰器

    @before_request

    #在执行视图函数之前,requset都要经过(before_request)

    @after_request(response)

    必须:return response

    #在执行视图函数之后,requset都要经过(after_request)

    @after_request/@before_request实例

    @app.before_request
    def x1():
        print('before:x1')
        return ''
    
    @app.before_request
    def xx1():
        print('before:xx1')
    
    @app.after_request
    def x2(response):
        print('after:x2')
        return response
    
    @app.after_request
    def xx2(response):
        print('after:xx2')
        return response
    
    @app.route('/index')
    def index():
        print('index')
        return "Index"        

    @template_global

    模板中有使用方法

    @template_filter

     模板中有使用方法

    @errorhandler

     出现错误时,自定制返回的内容

    @app.errorhandler(404)
    def not_found(arg):
      #arg 错误信息
    print(arg) return "没找到"

    蓝图

    目标:给开发者提供目录结构

    1.创建与项目名相同的文件夹

    2.在该文件下创建__init__.py

    from flask import Flask
    def create_app():
        app = Flask(__name__)
        return app

    3.在与文件同一级的目录下创建manage.py

    from crm import create_app
    app=create_app()
    if __name__ == '__main__':
        app.run()

    4.创建该项目的静态文件和模板

    5.蓝图的关系的创建

    user.py

    from flask import Blueprint
    us =Blueprint('us',__name__)
    @us.route('/login')
    def login():
        return 'login'
    @us.route('/logout')
    def logout():
        return 'logout'

    __init__.py

    from flask import Flask
    from .views.user import us
    def create_app():
        app = Flask(__name__)
        app.register_blueprint(us)
        return app

    6.蓝图前缀+before方法

    可以为每个蓝图加上前缀,比如127.0.0.1/admin/xxx/xxx

    127.0.0.1/web/xxx/xxx

    加上前缀:

    在__init__.py文件里面:

    from flask import Flask
    from .views.user import us
    from .views.account import ac
    def create_app():
        app = Flask(__name__)
        app.register_blueprint(us,url_prefix='/admin')
        app.register_blueprint(ac,url_prefix='/web')
        return app
    •  在__init__.py 里面加上@before_request 方法把所有的请求都会经过
    • 在每一个蓝图加上@before_request 那么就意味着只有该蓝驱的所有请求经过

     before_request源码流程图

     

     示例

    Session+Flask实现用户登录

    from flask import Flask,render_template,request,session,redirect
    
    app=Flask(__name__)
    
    #session 如果需要用到session 需要加盐.
    # 本质上他是放在cookies里,并不是像django一样放在数据库
    app.secret_key ='213fdasfa123df'
    
    @app.route('/login',methods=['GET','POST'])
    def Login():
        if request.method =='GET':
            return render_template('login.html')
        user=request.form.get('user')
        pwd=request.form.get('pwd')
        if user=='ming' and pwd=='123':
            session['user_info']={'username':user}
            return redirect('/index')
    
        return render_template('login.html',error='用户名或密码错误')
        # return render_template('login.html',**{'error':'用户名或者密码错误'})
    
    
    @app.route('/index')
    def index():
        user_info=session.get('user_info')
        if user_info:
            return render_template('index.html')
        return redirect('/login')
    
    if __name__ == '__main__':
        app.run()

     学生管理

    @app.route('/index')
    def index():
        if not session.get('user'):
            return redirect(url_for('login'))
        return render_template('index.html',stu_dic=STUDENT_DICT)
    #版本二:
    import functools
    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 render_template('index.html',stu_dic=STUDENT_DICT)
    
    #应用场景:比较少的函数中需要额外添加功能。
        
    #版本三:before_request
    @app.before_request
    def xxxxxx():
        if request.path == '/login':
            return None
    
        if session.get('user'):
            return None
    
        return redirect('/login')
  • 相关阅读:
    ffmpeg——压缩mav格式音频
    java控制台编译通过,运行出现找不到或无法加载主类的情况
    “Hello World!”团队——Final发布用户使用报告
    PSP总结报告
    软工第十二周个人PSP
    “Hello World!”团队第七周召开的第一次会议
    个人第十一周PSP
    互评Beta版本—博客园安卓APP
    sqlalchemy 学习笔记
    sqlite学习笔记
  • 原文地址:https://www.cnblogs.com/chenxuming/p/9414731.html
Copyright © 2011-2022 走看看