Uso Fast API para crear un servicio web.
Existen los siguientes modelos de sqlAlchemy:
class User(Base): __tablename__ = 'user' account_name = Column(String, primary_key=True, index=True, unique=True) email = Column(String, unique=True, index=True, nullable=False) roles = relationship("UserRole", back_populates="users", lazy=False, uselist=True) class UserRole(Base): __tablename__ = 'user_role' __table_args__ = (UniqueConstraint('role_name', 'user_name', name='user_role_uc'),) role_name = Column(String, ForeignKey('role.name'), primary_key=True) user_name = Column(String, ForeignKey('user.account_name'), primary_key=True) users = relationship("User", back_populates="roles")Los esquemas Pydantic están a continuación:
class UserRole(BaseModel): role_name: str class Config: orm_mode = True class UserBase(BaseModel): account_name: str email: EmailStr roles: List[UserRole] = [] class Config: orm_mode = TrueLo que tengo ahora es:
{ "account_name": "Test.Test", "email": "Test.Test@test.com", "roles": [ { "role_name": "all:admin" }, { "role_name": "all:read" } ] }Lo que quiero lograr es obtener un usuario de la API en la siguiente estructura:
{ "account_name": "Test.Test", "email": "Test.Test@test.com", "roles": [ "all:admin", "all:read" ] }¿Es eso posible? ¿Cómo debo cambiar los esquemas para obtener esto?
Si está de acuerdo con el manejo de la declaración del problema "obtener usuario de api" modificando la definición de la ruta fastapi, consulte a continuación.
¿Puede cambiar el modelo de respuesta utilizado por la definición de ruta fastapi para manejar el formato de salida deseado?
Ejemplo de definición de modelo de respuesta dinámica:
class UserResponse(BaseModel): account_name: str email: EmailStr roles: List[str]Ejemplo de consulta sqlalchemy + función de serialización:
def get_user_response(user_id) -> UserResponse: user = User.query.get(user_id) user_roles = UserRole.query.filter(user=user_id).all() role_names = [r.role_name for r in user_roles] response = UserResponse( account_name=user.account_name, email=user.email, roles=role_names } return responseEjemplo de definición de ruta fastapi:
@app.get("/users/{user_id}", response_model=UserResponse) async def read_item(user_id): return get_user_response(user_id)Consideraciones:
user_id de usuario para las consultas de los usuarios, pero esto se puede reemplazar con lo que termines usando como clave principal para esa tabla.UserResponse es muy similar a UserBase (podría subclasificar UserBase en lugar de model para evitar la redefinición de account_name y email , con la contrapartida de tener que anular la Config de la clase).UserBase que se serializa automáticamente cuando consulta el modelo de la base de datos y le permite eliminar o reducir el código en la función get_user_response() en la definición de ejemplo anterior.Como UserRole es una clase, se representa como un objeto (usando un diccionario). Si desea representarlo como una lista de cadenas, deberá transformar los datos (y cambiar la declaración de campo de su modelo Pydantic). Hay varios enfoques para esto, pero la documentación del modelo pydantic es un buen lugar para comenzar. Tenga en cuenta que el modelo ORM sirve como capa de representación de datos y el modelo pydantic es la capa de validación (y tal vez serialización), por lo que hay muchos lugares donde podría 'conectarse'.