
2.6 可插拔视图

在一些教程中,Pluggable Views也被翻译为“即插视图”,在本书中被翻译为“可插拔视图”。可插拔视图的含义是,可以在一个文件中编写多个功能类,每一个功能类对应显示一个视图功能。当在Flask Web程序中需要显示某个视图页面时,只需调用对应的功能类即可。调用这个功能类的方法就像插拔计算机中的U盘和内存卡那样,非常方便。在本节的内容中,将详细讲解在Flask Web程序中使用可插拔视图的方法。
2.6.1 使用可插拔视图
从Flask 0.7版本开始便引入了可插拔视图这一概念。可插拔视图的灵感来自Django框架中的通用视图,其基本原理是使用类来代替函数。使用可插拔视图的主要功能是利用可定制的、可插拔的视图灵活显示不同的页面内容。
假设现在想从数据库中查询用户数据,然后将查询到的数据载入到一个对象列表中并渲染到视图,上述功能可以通过下面的函数show_users()实现,具体实现代码如下。


通过上述代码,使用函数query.all()查询数据库中的用户信息,将查询到的信息渲染到模板文件users.html中并显示出来。这种函数实现的方法简单而灵活,但是如果想要用一种通用的、可以适应其他模型和模板文件的方式来提供这个视图,那么就需要更加灵活的机制。例如想在多个视图中使用上面的用户信息,此时可以使用基于类的可插拔视图技术来实现,具体实现流程如下所示。
(1)编写类
将上述查询并获取数据库中用户信息的功能转换为基于类的视图,例如下面的演示代码。

在上述代码中创建了类ShowUsers,并且定义了方法dispatch_request()。然后使用类ShowUsers的方法as_view()把这个类转换为一个实际的视图函数,传递给这个函数的字符串是视图的最终名称。
(2)代码重构
但是上面的实现方法还不够完美,接下来稍微重构一下代码。

虽然上面的例子非常简单,但是对于解释基本原则已经够用了。当有一个基于类的视图时,那么参数self指向什么。它工作的方式是,无论何时调度请求都会创建这个类的一个新实例,并且方法dispatch_request()会以URL规则进行参数调用。这个类本身会用传递到as_view()方法的参数来实现实例化操作。例如可以编写如下所示的类。

然后可以通过如下代码注册它。

(3)方法提示
通过可插拔视图,可以像常规函数一样用route()或add_url_rule()那样附加到应用中。但是在进行附加操作时,必须提供HTTP方法的名称。为了将这个信息加入到类中,可以使用属性methods来承载它。

(4)基于调度的方法
如果想对每个HTTP方法执行不同的函数,可以通过flask.views.MethodView技术实现,例如在下面的代码中,将每个HTTP方法映射到同名函数(只有名称为小写的)。如果不提供methods属性,则会自动的按照类中定义的方法来设置。

(5)装饰视图
因为视图类本身不是加入到路由系统的视图函数,所以装饰视图类并没有多大的意义。与之相反的是,可以手动装饰方法as_view()的返回值,具体实现代码如下。

从Flask 0.8版本开始,也可以在类的声明中设定一个装饰器列表的方法实现装饰视图,例如下面的演示代码。

注意:因为从调用者的角度看self是不明确的,所以不能在单独的视图方法上使用常规的视图装饰器。
2.6.2 可插拔视图实战演练
在下面的实例中,演示了在Flask Web程序中使用可插拔视图的过程。
源码路径:daima\2\2-6\chaba\
1)在视图文件views.py中定义两个可插拔视图类,在类UserView中设置了异常错误,执行后会调用运行我们编写的异常代码。文件views.py的具体实现代码如下所示。

2)编写文件myexceptions.py定义一个和身份验证相关的异常类AuthenticationException。在本实例中,我们故意设置发生上面定义的auth_error()异常。文件myexceptions.py的具体实现代码如下所示。

3)编写文件error_handlers.py实现基本的错误处理,通过两个函数分别实现未知错误的错误处理程序和用户输入数据发生异常时的错误处理程序。文件error_handlers.py的具体实现代码如下所示。


4)编写文件routing.py,在URL导航中使用UserView.as_view设置可插拔视图,具体实现代码如下所示。

5)编写两个模板文件users.html和error.html,用于分别显示出错页面和正常页面。
运行程序,在浏览器中输入“http://127.0.0.1:5000/”后会发生404错误,并显示出错页面error.html的内容。在浏览器中输入“http://127.0.0.1:5000/users”后会调用视图类UserView的内容,因为我们故意使用raise设置了异常,所以执行后最终会显示auth_error()函数中定义的JSON内容,如图2-10所示。

图2-10 执行效果
如果将视图文件views.py中的raise行代码删除,那么在浏览器中输入“http://127.0.0.1:5000/users”后会显示模板文件users.html的内容,如图2-11所示。

图2-11 删除raise行代码后的执行效果