Python Pydantic错误: TypeError: __init__()只接受一个位置参数(已给出2个)

6

我正在为大学开发一个Python FastAPI项目。每次运行我的授权依赖项时,都会出现以下错误:

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 366, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:\Python39\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "C:\Python39\lib\site-packages\fastapi\applications.py", line 208, in __call__
    await super().__call__(scope, receive, send)
  File "C:\Python39\lib\site-packages\starlette\applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:\Python39\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
    raise exc
  File "C:\Python39\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:\Python39\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    raise exc
  File "C:\Python39\lib\site-packages\starlette\exceptions.py", line 71, in __call__
    await self.app(scope, receive, sender)
  File "C:\Python39\lib\site-packages\starlette\routing.py", line 656, in __call__
    await route.handle(scope, receive, send)
  File "C:\Python39\lib\site-packages\starlette\routing.py", line 259, in handle
    await self.app(scope, receive, send)
  File "C:\Python39\lib\site-packages\starlette\routing.py", line 61, in app
    response = await func(request)
  File "C:\Python39\lib\site-packages\fastapi\routing.py", line 216, in app
    solved_result = await solve_dependencies(
  File "C:\Python39\lib\site-packages\fastapi\dependencies\utils.py", line 496, in solve_dependencies
    solved_result = await solve_dependencies(
  File "C:\Python39\lib\site-packages\fastapi\dependencies\utils.py", line 525, in solve_dependencies
    solved = await call(**sub_values)
  File "e:\Dev\Ottomize\Ottomize\backend\app\auth_handler.py", line 60, in get_current_user
    token_data = schemas.TokenData(username)
  File "pydantic\main.py", line 322, in pydantic.main.BaseModel.__init__
TypeError: __init__() takes exactly 1 positional argument (2 given)

这是我相关的代码:

FAST API 端点:

@app.get("/user/current/info/", response_model=schemas.User)
async def user_info(current_user: schemas.User = Depends(auth_handler.get_current_active_user)):
    return current_user

我在我的auth_handler.py中使用的函数:

from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
from typing import Optional


from fastapi import Depends, HTTPException, status
from . import crud, schemas, config, database

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

#gets user out of db
    def get_user(username: str):
        db = database.SessionLocal()
        return crud.get_user_by_username(db, username)

#gets current user
async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, config.SECRET_KEY, algorithms=[config.ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
        token_data = schemas.TokenData(username)
    except JWTError:
        raise credentials_exception
    user = get_user(token_data.username)
    if user is None:
        raise credentials_exception
    return user

#gets current user if active
async def get_current_active_user(current_user: schemas.User = Depends(get_current_user)):
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

我在我的crud.py中使用了以下函数:

def get_user_by_username(db: Session, username: str):
    return db.query(models.User).filter(models.User.username == username).first()

使用的SQLAlchemy模型:

from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship

from .database import Base

class User(Base):
    __tablename__ = "user"

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(100), unique=True, index=True)
    mail = Column(String(100), unique=True, index=True)
    hashed_password = Column(String(100))
    is_active = Column(Boolean, default=True)

    permissions = relationship("Permission", back_populates="user")

class Permission(Base):
    __tablename__ = "permission"

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(100))
    user_id = Column(Integer, ForeignKey("user.id"))
    
    user =  relationship("User", back_populates="permissions")

使用的pydantic模型:

from typing import List, Optional
from pydantic import BaseModel

#Define Datatype Token 
class Token(BaseModel):
    access_token: str
    token_type: str

#Define Datatype TokenData 
class TokenData(BaseModel):
    username: str

    class Config:
        orm_mode = True


#Define Datatype User 
class User(BaseModel):
    id: int
    username: str
    mail: str
    is_active: Optional[bool]
    permissions: List[Permission] = []

    class Config:
        orm_mode = True
      

我对 FastAPI 和 Python 一般的语言都非常陌生,希望能得到帮助!

1个回答

13

您需要给Pydantic指定提供值的

token_data = schemas.TokenData(username=username)
否则,Pydantic 不知道应该将父作用域中的变量 username 赋值给模式中的 username 属性。

1
看起来 Pydantic 有隐式关键字构造函数?没有位置参数。 - ruslaniv
使用位置参数很容易出错,因为您不能假设类中字段的顺序保持不变。如果在name之前定义了username并且只更改类定义中的第一个字段,您是否希望其行为发生更改?这可能会导致奇怪和奇特的错误(对于默认值的字段和没有默认值的字段如何处理?在这种情况下,所有具有默认值的字段都必须在类中最后定义)。 - MatsLindh
有人能指出Pydantic文档网站https://pydantic-docs.helpmanual.io/usage/models/的哪一部分规定我们需要为其“BaseModel”构造函数提供关键字吗? - hunterex
@hunterex 抱歉,我无法为您提供手册的参考(并非所有的负面和原因都在手册中)。您可以参考 Pydantic 存储库上的此问题,以了解 Pydantic 作者的一些原因:https://github.com/samuelcolvin/pydantic/issues/116 - 如果您不需要 BaseModel(但由于您明确提到了它,我无法确定),您可以使用数据类:https://pydantic-docs.helpmanual.io/usage/dataclasses/ (或者您可以编写一个帮助程序初始化器,它接受位置参数)。 - MatsLindh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接