在 Flask-RESTful 示例应用 posted here 中,TODOS
集合是一个全局变量。
注册Todo
资源后:
api.add_resource(Todo, '/todos/<string:todo_id>')
处理Web请求时,Todo
方法访问全局TODOS
变量。
相反,我希望在类中实例化API并传递一个TODOS
集合,它是一个类变量而不是全局变量。
使用 Flask-RESTful 时,允许资源类中的方法访问调用类提供的变量而不使用全局变量的正确方法是什么?
答案 0 :(得分:4)
我第一次看起来并不理解您,您可以使用classmethod
来构建您的API。然后将其添加为资源
from flask import Flask
from flask.ext.restful import Api
class SomeApi(Resource):
def get(self):
return self.response
@classmethod
def make_api(cls, response):
cls.response = response
return cls
class KillerApp(object):
def __init__(self):
self.app = Flask()
app_api = Api(self.app)
MyApi = SomeAPI.make_api({"key": "value"})
app_api.add_resource(MyApi, "/api/path")
def run(self)
self.app.run()
KillerApp().run()
答案 1 :(得分:3)
add_resource
接受两个参数resource_class_args
和resource_class_kwargs
,用于将参数传递给构造函数。 (source)
所以你可以有一个资源:
from flask_restful import Resource
class TodoNext(Resource):
def __init__(self, **kwargs):
# smart_engine is a black box dependency
self.smart_engine = kwargs['smart_engine']
def get(self):
return self.smart_engine.next_todo()
您可以将所需的依赖项注入TodoNext,如下所示:
smart_engine = SmartEngine()
api.add_resource(TodoNext, '/next',
resource_class_kwargs={ 'smart_engine': smart_engine })
答案 2 :(得分:0)
基于@Greg回答我在 init 方法中添加了初始化检查:
为flask-restful api创建并调用Todo Resource类:
todo = Todo.create(InMemoryTodoRepository())
api.add_resource(todo, '/api/todos/<todo_id>')
Todo Resource类:
from flask_restful import reqparse, abort, Resource
from server.ApiResources.DTOs.TodoDTO import TodoDTO
from server.Repositories.ITodoRepository import ITodoRepository
from server.Utils.Exceptions import InvalidInstantiationError
from server.Utils.GeneralUtils import member_exists
class Todo(Resource):
"""shows a single todo item and lets you delete a todo item
use the 'create' class method to instantiate the class
"""
def __init__(self):
if not member_exists(self, "todo_repository", of_type=ITodoRepository):
raise InvalidInstantiationError("Todo", "todo_repository", "ITodoRepository", "create")
self._parser = reqparse.RequestParser()
self._parser.add_argument('task', type=str)
@classmethod
def create(cls, todo_repository):
"""
:param todo_repository: an instance of ITodoRepository
:return: class object of Todo Resource
"""
cls.todo_repository = todo_repository
return cls
member_exists辅助方法:
def member_exists(obj, member, of_type):
member_value = getattr(obj, member, None)
if member_value is None:
return False
if not isinstance(member_value, of_type):
return False
return True
和自定义异常类:
class InvalidInstantiationError(Exception):
def __init__(self, origin_class_name, missing_argument_name, missing_argument_type, instantiation_method_to_use):
message = """Invalid instantiation for class '{class_name}':
missing instantiation argument '{arg}' of type '{arg_type}'.
Please use the '{method_name}' factory class method""" \
.format(class_name=origin_class_name,
arg=missing_argument_name,
arg_type=missing_argument_type,
method_name=instantiation_method_to_use)
# Call the base class constructor with the parameters it needs
super(InvalidInstantiationError, self).__init__(message)
因此,尝试使用默认构造函数将最终获得此异常:
server.Utils.Exceptions.InvalidInstantiationError:类'Todo'的实例化无效: 缺少'ITodoRepository'类型的实例化参数'todo_repository'。 请使用'创建'工厂类方法
编辑:这对于使用依赖注入与flask-restful api资源类(使用或不使用IoC)非常有用
编辑2:
我们甚至可以更清洁并添加另一个帮助功能(准备导入):
def must_have(obj, member, of_type, use_method):
if not member_exists(obj, member, of_type=of_type):
raise InvalidInstantiationError(obj.__class__.__name__,
member,
of_type.__name__,
use_method)
然后在构造函数中使用它:
from server.Utils.GeneralUtils import must_have
class Todo(Resource):
def __init__(self):
must_have(self,
member="todo_repository",
of_type=ITodoRepository,
use_method=Todo.create.__name__)