写个验证用户登录的装饰器:在调用函数前,先检查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 = ''

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

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

最新文章

  1. [原]excel启动时死锁
  2. 数论 UVAlive 2889
  3. collectionView布局原理及瀑布流布局方式
  4. HTML5应用程序缓存Application Cache详解
  5. 针对IE的CSS hack 全面 实用
  6. 学习linux之vi编辑器
  7. 《Qt编程的艺术》——5.1 手动布局
  8. 非阻塞IOserver型号
  9. OpenCV框架介绍
  10. 利用firefox调试安卓手机端web
  11. 【记录一次windows技术学习】使用笔记本DOS命令搭建WLAN热点
  12. HTML常用标签属性使用
  13. WordPress 实现附件上传自动重命名但不改变附件标题
  14. Pandas与Matplotlib基础
  15. Vue打包优化之分析工具webpack-bundle-analyzer
  16. C语言常见易错题集(分析及解答)(仅可用于交流,勿用于商业用途)
  17. Sql Server数据库之触发器
  18. svn&#160;checkout&#160;实用小技巧
  19. 项目中Java Resources有红叉,其它没有,解决办法
  20. linux经常使用命令-帮助命令-授之以渔

热门文章

  1. 【Luogu2759】奇怪的函数(数论)
  2. 300行Kotlin代码实现的区块链
  3. c# ffmpeg视频转换【转载】
  4. 我对asp.net运行机制的理解
  5. uwsgi服务启动(start)停止(stop)重新装载(reload)
  6. CYQ.data 框架结构
  7. python计算机基础-Day1
  8. Linux上部署SVN
  9. 共享MFC自绘Listctrl代码
  10. 解决html5 canvas 绘制字体、图片与图形模糊问题