Flask-RESTful如何add_resource并传递非全局数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask-RESTful如何add_resource并传递非全局数据相关的知识,希望对你有一定的参考价值。

Flask-RESTful示例应用程序posted here中,TODOS集合是一个全局变量。

Todo资源注册后:

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

当处理Web请求时,Todo方法访问全局TODOS变量。

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

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

答案

看起来我第一次不理解你,你可以使用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()
另一答案

add_resource接受两个参数,resource_class_argsresource_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 })
另一答案

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

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

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'。请使用'create'工厂类方法

编辑:这可以用于使用依赖注入与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__)

以上是关于Flask-RESTful如何add_resource并传递非全局数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Flask-USER 管理保护 Flask-RESTful?

如何将 flask.url_for() 与 flask-restful 一起使用?

Flask-RESTful - 上传图片

如何使用客户端上的“requests”模块和服务器上的“flask-restful”验证 https 请求的自签名证书(TLS1.2)

Flask-RESTful中装饰器的使用

flask-restful 组件