为可扩展功能划分Flask可插入视图子类的最佳方式



我正在构建一个Web应用程序,在该应用程序中,不同的视图将具有不同数量的"封装功能"(例如身份验证、日志记录/错误处理、数据库访问等(,并且能够在视图之间轻松共享此功能。

我认为Pluggable视图将是处理这一问题的好方法,通过反复对视图进行子类化来构建功能层,从而封装视图的主要操作。

然而,我正在努力找出实现这一点的最佳方法。我正在考虑链接装饰器,但继承似乎不太好用。

例如,具有一些自定义日志记录和错误处理的简化视图:

from flask.views import View
class LoggedView(View):
def __init__(self,template):
self.template=template
#Decorator method for error handling and logging
def log_view(self,view):
def decorator(**kwargs):
try:
#Set up custom logging
self.log = .....
#Execute view
return view(**kwargs)
except CustomApplicationError as e:
#Log and display error
self.log.error(e)
return render_template('error.html',error=str(e))
return decorator
decorators=[log_view]
#This can be overridden for more complex views
def dispatch_request(self):
return render_template(self.template)

视图可以像这样使用:

app.add_url_rule('/index', view_func=LoggedView.as_view('index',template='index.html'))

然后,如果我想在这个视图的基础上添加用户身份验证:

class RestrictedView(LoggedView):
#Decorator method for user access validation
def validate_access(self,view):
def decorator(**kwargs):
g.user=session.get('user')
if g.user is None:
return redirect(url_for('login'))
#Execute view
return view(**kwargs)
return decorator
#How to add this functionality to the decorator chain? e.g. I dont think this works: 
decorators.append(validate_access)

然后我想重复这个子类化,以添加更多的功能,如数据库访问

  • 有更好的方法来实现我想要做的事情吗
  • 将decorator作为视图方法有意义吗?在装饰器中使用"self"是否有效

如有任何建议,我们将不胜感激!

decorators是一个列表,一个可变结构。你不能只是在一个子类中附加到它上面。名称decorators不是在子类中定义的,如果您将其附加到LoggedView.decorators,那么您将附加到错误的列表中!

您必须在子类中创建一个新的列表对象来屏蔽基类上的属性;您可以通过连接到基类序列来构造一个;我在这里使用了元组以使其更清楚:

class LoggedView(View):
decorators = (log_view,)
class RestrictedView(LoggedView):
decorators = LoggedView.decorators + (validate_access,)

请注意,decorator是而不是方法,它们在应用时没有绑定到视图,因此没有self参数。

如果你需要从装饰器访问视图实例,那么不要使用View.decorators,这些装饰器会装饰一个简单的函数,当被调用时,该函数会在对该视图调用View.dispatch_request()之前创建视图;调用CCD_ 7时返回的就是这个简单的函数。另一方面,如果您需要能够访问装饰器在注册路由时或(在另一个方向上(在查找端点的注册视图时生成的包装器,那么使用View.decorators是完全正确的。

您可以直接修饰方法(包括dispatch_request()(,也可以在dispatch_request():中实现自己的机制

import inspect
class LoggedView(View):
method_decorators = (log_view,)
#This can be overridden for more complex views
def dispatch_request(self):
# decorate methods
cls = type(self)
members = vars(type(self)).items()
for name, object in members:
if not inspect.isfunction(object):
continue
if name == 'dispatch_request':
continue
# add bound decorated functions to the view
for d in self.method_decorators:
setattr(self, name, d(object).__get__(self, cls))
# dispatch
return render_template(self.template)

这是Flask RESTFul项目使用的路径,它允许用一行代码为视图上的所有方法指定decorator。

然后从包装调用参数中提取self参数(但一定要将其传递给包装函数(:

def log_view(view):
def decorator(self, **kwargs):
try:
#Set up custom logging
self.log = .....
#Execute view
return view(self, **kwargs)
except CustomApplicationError as e:
#Log and display error
self.log.error(e)
return render_template('error.html',error=str(e))
return decorator

我会在视图类的外部定义decorator函数本身

最新更新