类视图

我们之前定义的视图都是用函数实现的,所以叫作函数视图。视图也可以使用类实现,即叫作类视图。类视图的好处是可以使用继承,把一些脚手架代码在父类中写好,子类只要聚焦到核心代码即可,从而为开发者节省时间。

基本使用

使用 Flask 类视图需要继承自 flask.views.View 类,然后在子类中实现 dispatch_request 方法,这个方法类似于视图函数,可以进行逻辑处理,并且需要返回一个响应。这里以返回所有用户列表为例,用视图函数来实现,示例代码如下。

from flask.views import View

class ShowUsers(View):
    def dispatch_request(self):
        users = User.query.all()
        return render_template('users.html', objects=users)

app.add_url_rule('/users/', view_func=ShowUsers.as_view('show_users'))

以上代码中,首先从 flask.views 中导入 View,然后定义类视图 ShowUsers,让其继承自View。接着实现dispatch_request方法,在这个方法中,我们从数据库中获取所有的用户,并且渲染模板,其操作方式跟视图函数一样。最后再把类视图,通过app.add_url_rule方法与路由进行绑定,在绑定的时候,必须通过as_view()方法,把类转换为实际的视图函数,传给as_view方法的字符串参数是视图函数的名称,以后通过url_for进行反转时,需要使用到这个名称。此时用类视图并没有发现有什么优势,那么我们重构一下,把脚手架代码在父类中提前定义好,用子类去实现核心代码即可,示例代码如下。

from flask.views import View

class ListView(View):
    def get_template_name(self):
        raise NotImplementedError()

    def render_template(self, context):
        return render_template(self.get_template_name(), **context)

    def dispatch_request(self):
        context = {'objects': self.get_objects()}
        return self.render_template(context)

class UserView(ListView):
    def get_template_name(self):
        return 'users.html'

    def get_objects(self):
        return User.query.all()

上述代码中,定义了一个ListView父视图,在这个父视图中提前定义好了用于获取模板的get_template_name方法,因为父视图无法知道具体的模板,所以抛出NotImplementedError异常,因此子视图必须要实现这个方法,并且返回模板路径。此外,还定义了用于渲染模板的render_template方法,以及分发请求的dispatch_request方法。子视图UserView分别实现了get_template_name和get_objects方法,这样子视图就在代码量最小的情况下实现了列表渲染功能。

方法限制

在函数视图中,通过@app.route的methods参数即可限制请求的方法。类视图则通过定义methods类属性实现限制请求的功能,示例代码如下。

class MyView(View):
    methods = ['GET', 'POST']

    def dispatch_request(self):
        if request.method == 'POST':
            # Your POST handling logic here
            pass
        else:
            # Your GET handling logic here
            pass

app.add_url_rule('/myview', view_func=MyView.as_view('myview'))

上述代码中,在MyView中定义了methods属性,以后这个类视图就只能通过GET和POST方法进行访问了。

基于方法的类视图

现在的类视图是通过判断request.method来实现不同方法的逻辑代码,如果让子视图继承自flask.views.MethodView,则可以在类视图中重写对应小写形式的方法,如GET请求则实现get方法,POST请求则实现post方法,flask会自动根据浏览器请求的HTTP方法执行对应的方法,示例代码如下。

from flask.views import MethodView

class UserAPI(MethodView):
    def get(self):
        users = User.query.all()
        # Your logic to return the users
        pass

    def post(self):
        user = User.from_form_data(request.form)
        # Your logic to process the user data
        pass

app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))

以后在访问/users/这个URL时,如果用GET方法请求,那么就会执行UserAPI的get方法,用POST方法请求,就会执行UserAPI的post方法,示例代码如下。

class UserAPI(MethodView):
    def get(self):
        users = User.query.all()
        # Your logic to return the users
        pass

    def post(self):
        user = User.from_form_data(request.form)
        # Your logic to process the user data
        pass

app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))

添加装饰器

在类视图中,如果想要添加装饰器,如某些视图需要登录才能访问,则可以在类视图中定义一个类属性decorators来实现,示例代码如下。

class UserAPI(MethodView):
    decorators = [user_required]

以上代码中,user_required 是自定义的装饰器,读者可以自行实现。