zoukankan      html  css  js  c++  java
  • Flask 视图

    写个验证用户登录的装饰器:在调用函数前,先检查session里有没有用户

    from functools import wraps
    from flask import session, abort
     
    def login_required(func):
        @wraps(func)
        def decorated_function(*args, **kwargs):
            if not 'user' in session:
                abort(401)
            return func(*args, **kwargs)
        return decorated_function
     
    app.secret_key = '12345678'

    需将此装饰器加在每个需要验证登录的请求方法上即可

    @app.route('/admin')
    @login_required
    def admin():
        return '<h1>Admin Dashboard</h1>'

    URL集中映射

    Flask也支持像Django一样,把URL路由规则统一管理,而不是写在视图函数上

    我们先来写个视图函数,将它放在一个”views.py”文件中:

    def foo():
        return '<h1>Hello Foo!</h1>'

    然后在Flask主程序上调用”app.add_url_rule”方法:

        
    app.add_url_rule('/foo', view_func=views.foo)

    这样,路由”/foo”就绑定在”views.foo()”函数上了,效果等同于在”views.foo()”函数上加上”@app.route(‘/foo’)”装饰器。通过”app.add_url_rule”方法,我们就可以将路由同视图分开,将路由统一管理,实现完全的MVC。

    装饰器本质上是一个闭包函数,所以我们当然可以把它当函数使用:

    app.add_url_rule('/foo', view_func=login_required(views.foo))

    可插拔视图Pluggable View

    from flask.views import View
     
    class HelloView(View):
        def dispatch_request(self, name=None):
            return render_template('hello-view.html', name=name)
     
    view = HelloView.as_view('helloview')
    app.add_url_rule('/helloview', view_func=view)
    app.add_url_rule('/helloview/<name>', view_func=view)

    我们创建了一个”flask.views.View”的子类,并覆盖了其”dispatch_request()”函数,渲染视图的主要代码必须写在这个函数里。然后我们通过”as_view()”方法把类转换为实际的视图函数,”as_view()”必须传入一个唯一的视图名。此后,这个视图就可以由”app.add_url_rule”方法绑定到路由上了。上例的效果,同本篇第一节中”/hello”路径的效果,完全一样。

    这个例子比较简单,只是为了介绍怎么用视图类,体现不出它的灵活性,我们再看个例子:

    class RenderTemplateView(View):
        def __init__(self, template):
            self.template = template
     
        def dispatch_request(self):
            return render_template(self.template)
     
    app.add_url_rule('/hello', view_func=RenderTemplateView.as_view('hello', template='hello-view.html'))
    app.add_url_rule('/login', view_func=RenderTemplateView.as_view('login', template='login-view.html'))

    视图装饰器支持

    class HelloView(View):
        decorators = [login_required]
     
        def dispatch_request(self, name=None):
            return render_template('hello-view.html', name=name)

    我们只需将装饰器函数加入到视图类变量”decorators”中即可。它是一个列表,所以能够支持多个装饰器,并按列表中的顺序执行。

    请求方法的支持

    当我们的视图要同时支持GET和POST请求时,视图类可以这么定义:

    class MyMethodView(View):
        methods = ['GET', 'POST']
     
        def dispatch_request(self):
            if request.method == 'GET':
                return '<h1>Hello World!</h1>This is GET method.'
            elif request.method == 'POST':
                return '<h1>Hello World!</h1>This is POST method.'
     
    app.add_url_rule('/mmview', view_func=MyMethodView.as_view('mmview'))

    我们只需将需要支持的HTTP请求方法加入到视图类变量”methods”中即可。没加的话,默认只支持GET请求。

    基于方法的视图

    上节介绍的HTTP请求方法的支持,的确比较方便,但是对于RESTFul类型的应用来说,有没有更简单的方法,比如省去那些if, else判断语句呢?Flask中的”flask.views.MethodView”就可以做到这点,它是”flask.views.View”的子类。我们写个user API的视图吧:

    from flask.views import MethodView
     
    class UserAPI(MethodView):
        def get(self, user_id):
            if user_id is None:
                return 'Get User called, return all users'
            else:
                return 'Get User called with id %s' % user_id
     
        def post(self):
            return 'Post User called'
     
        def put(self, user_id):
            return 'Put User called with id %s' % user_id
     
        def delete(self, user_id):
            return 'Delete User called with id %s' % user_id

    现在我们分别定义了get, post, put, delete方法来对应四种类型的HTTP请求,注意函数名必须这么写。怎么将它绑定到路由上呢?

    user_view = UserAPI.as_view('users')
    # 将GET /users/请求绑定到UserAPI.get()方法上,并将get()方法参数user_id默认为None
    app.add_url_rule('/users/', view_func=user_view, 
                                defaults={'user_id': None}, 
                                methods=['GET',])
    # 将POST /users/请求绑定到UserAPI.post()方法上
    app.add_url_rule('/users/', view_func=user_view, 
                                methods=['POST',])
    # 将/users/<user_id>URL路径的GET,PUT,DELETE请求,
    # 绑定到UserAPI的get(), put(), delete()方法上,并将参数user_id传入。
    app.add_url_rule('/users/<user_id>', view_func=user_view, 
                                         methods=['GET', 'PUT', 'DELETE'])

    上例中”app.add_url_rule()”可以传入参数default,来设置默认值;参数methods,来指定支持的请求方法。

    如果API多,有人觉得每次都要加这么三个路由规则太麻烦,可以将其封装个函数:

    def register_api(view, endpoint, url, primary_id='id', id_type='int'):
        view_func = view.as_view(endpoint)
        app.add_url_rule(url, view_func=view_func,
                              defaults={primary_id: None},
                              methods=['GET',])
        app.add_url_rule(url, view_func=view_func,
                              methods=['POST',])
        app.add_url_rule('%s<%s:%s>' % (url, id_type, primary_id),
                              view_func=view_func,
                              methods=['GET', 'PUT', 'DELETE'])
     
    register_api(UserAPI, 'users', '/users/', primary_id='user_id')

    现在,一个”register_api()”就可以绑定一个API了

    延迟加载视图

    当某一视图很占内存,而且很少会被使用,我们会希望它在应用启动时不要被加载,只有当它被使用时才会被加载。也就是接下来要介绍的延迟加载。Flask原生并不支持视图延迟加载功能,但我们可以通过代码实现。这里,我引用了官方文档上的一个实现。

    from werkzeug import import_string, cached_property
     
    class LazyView(object):
        def __init__(self, import_name):
            self.__module__, self.__name__ = import_name.rsplit('.', 1)
            self.import_name = import_name
     
        @cached_property
        def view(self):
            return import_string(self.import_name)
     
        def __call__(self, *args, **kwargs):
            return self.view(*args, **kwargs)
    def bar():
        return '<h1>Hello Bar!</h1>'

    我们先写了一个LazyView,然后在views.py中定义一个名为bar的视图函数:

    现在让我们来绑定路由:

    app.add_url_rule('/lazy/bar', view_func=LazyView('views.bar'))

    路由绑定在LazyView的对象上,因为实现了__call__方法,所以这个对象可被调用,不过只有当’/lazy/bar’地址被请求时才会被调用。此时”werkzeug.import_string”方法会被调用,看了下Werkzeug的源码,它的本质就是调用”__import__”来动态地导入Python的模块和函数。所以,这个”view.bar”函数只会在’/lazy/bar’请求发生时才被导入到主程序中。不过要是每次请求发生都被导入一次的话,开销也很大,所以,代码使用了”werkzeug.cached_property”装饰器把导入后的函数缓存起来

    同上一节的”register_api()”函数一样,你也可以把绑定延迟加载视图的代码封装在一个函数里。

    def add_url_for_lazy(url_rule, import_name, **options):
        view = LazyView(import_name)
        app.add_url_rule(url_rule, view_func=view, **options)
     
    add_url_for_lazy('/lazy/bar', 'views.bar')
  • 相关阅读:
    Global.asax 文件是什么
    C和C++语言学习总结
    iphone窗口传值
    c语言实现队列
    iphone窗口跳转
    NSStirng、NSArray、 文件 以及枚举(Method小集合)
    服务器接受的链接过多,该怎么处理
    c语言实现单链表
    iphone开发 NSXMLParser解析xml文件
    iphone 切换界面
  • 原文地址:https://www.cnblogs.com/Erick-L/p/7007090.html
Copyright © 2011-2022 走看看