猿问

如何在类中使用 FastAPI 创建路由

所以我需要在类中拥有一些路由,但路由方法需要具有 attr self(以访问类的属性)。然而,FastAPI 然后假设self是它自己的必需参数并将其作为查询参数放入


这就是我所拥有的:


app = FastAPI()

class Foo:

    def __init__(y: int):

        self.x = y


    @app.get("/somewhere")

    def bar(self): return self.x

但是,422除非您转到 ,否则该命令将会返回/somewhere?self=something。问题在于,这是selfstr,因此毫无用处。


我需要一些我仍然可以访问的方法,self而无需将其作为必需参数。


慕盖茨4494581
浏览 461回答 5
5回答

胡子哥哥

APIRouter这可以通过使用 an的方法来完成add_api_route:from fastapi import FastAPI, APIRouterclass Hello:&nbsp; &nbsp; def __init__(self, name: str):&nbsp; &nbsp; &nbsp; &nbsp; self.name = name&nbsp; &nbsp; &nbsp; &nbsp; self.router = APIRouter()&nbsp; &nbsp; &nbsp; &nbsp; self.router.add_api_route("/hello", self.hello, methods=["GET"])&nbsp; &nbsp; def hello(self):&nbsp; &nbsp; &nbsp; &nbsp; return {"Hello": self.name}app = FastAPI()hello = Hello("World")app.include_router(hello.router)例子:$ curl 127.0.0.1:5000/hello{"Hello":"World"}add_api_route的第二个参数 ( endpoint) 具有 type Callable[..., Any],因此任何可调用都应该可以工作(只要 FastAPI 可以找到如何解析其参数 HTTP 请求数据)。此可调用函数在 FastAPI 文档中也称为路径操作函数(下面称为“POF”)。为什么装饰方法不起作用警告:如果您对OP答案中的代码不起作用的技术解释不感兴趣,请忽略此答案的其余部分在类主体中使用 and 朋友装饰方法@app.get是行不通的,因为您将有效地传递Hello.hello,而不是hello.hello(又名self.hello)到add_api_route。绑定和非绑定方法(自 Python 3 起简称为“函数” )具有不同的签名:import inspectinspect.signature(Hello.hello)&nbsp; # <Signature (self)>inspect.signature(hello.hello)&nbsp; # <Signature ()>FastAPI 做了很多魔法来尝试自动将 HTTP 请求中的数据(正文或查询参数)解析为 POF 实际使用的对象。通过使用未绑定方法(=常规函数)( Hello.hello) 作为 POF,FastAPI 必须:对包含路由的类的性质做出假设并动态生成self(也称为调用Hello.__init__)。这可能会给 FastAPI 增加很多复杂性,并且 FastAPI 开发人员(可以理解)似乎对支持这个用例不感兴趣。处理应用程序/资源状态的推荐方法似乎是将整个问题推迟到Depends.以某种方式能够self从调用者发送的 HTTP 请求数据(通常是 JSON)生成对象。这在技术上对于字符串或其他内置函数之外的任何东西都是不可行的,因此实际上不可用。OP 代码中发生的情况是#2。FastAPI 尝试从 HTTP 请求查询参数中解析Hello.hello(= self,类型) 的第一个参数,显然失败并引发,该参数作为 HTTP 422 响应显示给调用者。HelloRequestValidationErrorself从查询参数解析只是为了证明上面的#2,这里有一个(无用的)示例,说明 FastAPI 何时可以真正self从 HTTP 请求中“解析”:(免责声明:请勿将以下代码用于任何实际应用)from fastapi import FastAPIapp = FastAPI()class Hello(str):&nbsp; &nbsp; @app.get("/hello")&nbsp; &nbsp; def hello(self):&nbsp; &nbsp; &nbsp; &nbsp; return {"Hello": self}例子:$ curl '127.0.0.1:5000/hello?self=World'{"Hello":"World"}

30秒到达战场

要创建基于类的视图,您可以使用fastapi-utils中的@cbv装饰器。使用它的动机:停止在相关端点的签名中一遍又一遍地重复相同的依赖关系。您的示例可以这样重写:from fastapi import Depends, FastAPIfrom fastapi_utils.cbv import cbvfrom fastapi_utils.inferring_router import InferringRouterdef get_x():    return 10app = FastAPI()router = InferringRouter()  # Step 1: Create a router@cbv(router)  # Step 2: Create and decorate a class to hold the endpointsclass Foo:    # Step 3: Add dependencies as class attributes    x: int = Depends(get_x)    @router.get("/somewhere")    def bar(self) -> int:        # Step 4: Use `self.<dependency_name>` to access shared dependencies        return self.xapp.include_router(router)

人到中年有点甜

我不喜欢这样做的标准方法,所以我编写了自己的库。你可以像这样安装它:$ pip install cbfa以下是如何使用它的示例:from typing import Optionalfrom fastapi import FastAPIfrom pydantic import BaseModelfrom cbfa import ClassBasedapp = FastAPI()wrapper = ClassBased(app)class Item(BaseModel):&nbsp; &nbsp; name: str&nbsp; &nbsp; price: float&nbsp; &nbsp; is_offer: Optional[bool] = None@wrapper('/item')class Item:&nbsp; &nbsp; def get(item_id: int, q: Optional[str] = None):&nbsp; &nbsp; &nbsp; &nbsp; return {"item_id": item_id, "q": q}&nbsp; &nbsp; def post(item_id: int, item: Item):&nbsp; &nbsp; &nbsp; &nbsp; return {"item_name": item.name, "item_id": item_id}请注意,您不需要在每个方法周围包装装饰器。根据方法在 HTTP 协议中的用途来命名这些方法就足够了。整个类都变成了一个装饰器。

慕沐林林

我把路线放到def __init__. 它工作正常。例子:from fastapi import FastAPIfrom fastapi.responses import HTMLResponseclass CustomAPI(FastAPI):&nbsp; &nbsp; def __init__(self, title: str = "CustomAPI") -> None:&nbsp; &nbsp; &nbsp; &nbsp; super().__init__(title=title)&nbsp; &nbsp; &nbsp; &nbsp; @self.get('/')&nbsp; &nbsp; &nbsp; &nbsp; async def home():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Home page&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return HTMLResponse("<h1>CustomAPI</h1><br/><a href='/docs'>Try api now!</a>", status_code=status.HTTP_200_OK)

喵喔喔

我刚刚发布了一个项目,允许您使用类实例通过简单的装饰器进行路由处理。cbv很酷,但路由是在类本身上,而不是类的实例上。能够使用类实例可以让您以一种对我来说更简单、更直观的方式进行依赖项注入。例如,以下内容按预期工作:from classy_fastapi import Routable, get, deleteclass UserRoutes(Routable):   """Inherits from Routable."""   # Note injection here by simply passing values   # to the constructor. Other injection frameworks also    # supported as there's nothing special about this __init__ method.   def __init__(self, dao: Dao) -> None:      """Constructor. The Dao is injected here."""      super().__init__()      self.__dao = Dao   @get('/user/{name}')   def get_user_by_name(name: str) -> User:      # Use our injected DAO instance.      return self.__dao.get_user_by_name(name)   @delete('/user/{name}')   def delete_user(name: str) -> None:      self.__dao.delete(name)def main():    args = parse_args()    # Configure the DAO per command line arguments    dao = Dao(args.url, args.user, args.password)    # Simple intuitive injection    user_routes = UserRoutes(dao)        app = FastAPI()    # router member inherited from Routable and configured per the annotations.    app.include_router(user_routes.router)您可以在 PyPi 上找到它并通过 进行安装pip install classy-fastapi。
随时随地看视频慕课网APP

相关分类

Python
我要回答