4

此处发布的Flask-RESTful示例应用程序中,集合是一个全局变量。TODOS

Todo 资源注册后:

api.add_resource(Todo, '/todos/<string:todo_id>')

这些Todo方法在处理 Web 请求时访问全局TODOS变量。

相反,我想在一个类中实例化 API,并传递一个TODOS作为类变量而不是全局变量的集合。

使用Flask-RESTful时,允许Resource类中的方法在不使用全局变量的情况下访问调用类提供的变量的正确方法是什么?

4

3 回答 3

4

看来我第一次没看懂你,你可以用 aclassmethod来构建你的 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()
于 2013-09-29T05:08:42.480 回答
4

add_resource接受两个参数,resource_class_argsresource_class_kwargs,用于将参数传递给构造函数。(来源

所以你可以有一个资源:

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 })
于 2016-09-09T19:37:11.647 回答
0

基于@Greg 的回答,我在init方法中添加了一个初始化检查:

为 flask-restful api 创建和调用 Todo 资源类:

todo = Todo.create(InMemoryTodoRepository())
api.add_resource(todo, '/api/todos/<todo_id>')

Todo 资源类:

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__)
于 2015-04-12T14:29:58.783 回答