From e5005ad93f25254a537cfe69381d58e5df6c2412 Mon Sep 17 00:00:00 2001 From: BrunoNunesdaSilva427 Date: Wed, 11 Jun 2025 14:56:14 -0300 Subject: [PATCH 1/4] Update schemas.py --- workout_api/atleta/schemas.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/workout_api/atleta/schemas.py b/workout_api/atleta/schemas.py index f3e33d36..a76305b3 100644 --- a/workout_api/atleta/schemas.py +++ b/workout_api/atleta/schemas.py @@ -15,7 +15,14 @@ class Atleta(BaseSchema): sexo: Annotated[str, Field(description='Sexo do atleta', example='M', max_length=1)] categoria: Annotated[CategoriaIn, Field(description='Categoria do atleta')] centro_treinamento: Annotated[CentroTreinamentoAtleta, Field(description='Centro de treinamento do atleta')] + +class AtletaListOut(BaseSchema): + nome: Annotated[str, Field(description="Nome do atleta", example="Joao")] + centro_treinamento: CentroTreinamentoAtleta + categoria: CategoriaIn + class Config: + orm_mode = True class AtletaIn(Atleta): pass @@ -26,4 +33,4 @@ class AtletaOut(Atleta, OutMixin): class AtletaUpdate(BaseSchema): nome: Annotated[Optional[str], Field(None, description='Nome do atleta', example='Joao', max_length=50)] - idade: Annotated[Optional[int], Field(None, description='Idade do atleta', example=25)] \ No newline at end of file + idade: Annotated[Optional[int], Field(None, description='Idade do atleta', example=25)] From ff796bed16adccd61a8206476529f3400ff1a891 Mon Sep 17 00:00:00 2001 From: BrunoNunesdaSilva427 Date: Wed, 11 Jun 2025 15:00:45 -0300 Subject: [PATCH 2/4] Update controller.py --- workout_api/atleta/controller.py | 52 +++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/workout_api/atleta/controller.py b/workout_api/atleta/controller.py index b3a28d4c..571ee7f8 100644 --- a/workout_api/atleta/controller.py +++ b/workout_api/atleta/controller.py @@ -1,18 +1,27 @@ -from datetime import datetime +from datetime import datetime from uuid import uuid4 -from fastapi import APIRouter, Body, HTTPException, status +from fastapi import APIRouter, Body, HTTPException, Query, status from pydantic import UUID4 +from sqlalchemy.future import select +from sqlalchemy.exc import IntegrityError -from workout_api.atleta.schemas import AtletaIn, AtletaOut, AtletaUpdate +from workout_api.atleta.schemas import ( + AtletaIn, + AtletaOut, + AtletaUpdate, + AtletaListOut +) from workout_api.atleta.models import AtletaModel from workout_api.categorias.models import CategoriaModel from workout_api.centro_treinamento.models import CentroTreinamentoModel from workout_api.contrib.dependencies import DatabaseDependency -from sqlalchemy.future import select + +from fastapi_pagination import Page, paginate, add_pagination router = APIRouter() + @router.post( '/', summary='Criar um novo atleta', @@ -45,6 +54,7 @@ async def post( status_code=status.HTTP_400_BAD_REQUEST, detail=f'O centro de treinamento {centro_treinamento_nome} não foi encontrado.' ) + try: atleta_out = AtletaOut(id=uuid4(), created_at=datetime.utcnow(), **atleta_in.model_dump()) atleta_model = AtletaModel(**atleta_out.model_dump(exclude={'categoria', 'centro_treinamento'})) @@ -54,6 +64,12 @@ async def post( db_session.add(atleta_model) await db_session.commit() + except IntegrityError: + await db_session.rollback() + raise HTTPException( + status_code=status.HTTP_303_SEE_OTHER, + detail=f"Já existe um atleta cadastrado com o cpf: {atleta_in.cpf}" + ) except Exception: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -64,15 +80,25 @@ async def post( @router.get( - '/', - summary='Consultar todos os Atletas', + '/', + summary='Consultar todos os Atletas com filtros e paginação', status_code=status.HTTP_200_OK, - response_model=list[AtletaOut], + response_model=Page[AtletaListOut], ) -async def query(db_session: DatabaseDependency) -> list[AtletaOut]: - atletas: list[AtletaOut] = (await db_session.execute(select(AtletaModel))).scalars().all() - - return [AtletaOut.model_validate(atleta) for atleta in atletas] +async def query( + db_session: DatabaseDependency, + nome: str | None = Query(default=None, description="Filtrar por nome do atleta"), + cpf: str | None = Query(default=None, description="Filtrar por CPF do atleta"), +): + stmt = select(AtletaModel) + + if nome: + stmt = stmt.filter(AtletaModel.nome.ilike(f"%{nome}%")) + if cpf: + stmt = stmt.filter(AtletaModel.cpf == cpf) + + result = (await db_session.execute(stmt)).scalars().all() + return paginate(result) @router.get( @@ -140,3 +166,7 @@ async def delete(id: UUID4, db_session: DatabaseDependency) -> None: await db_session.delete(atleta) await db_session.commit() + + +# Adiciona suporte à paginação no router +add_pagination(router) From 0dec1b9f01d9e53d845fe6e13198115b948e53ec Mon Sep 17 00:00:00 2001 From: BrunoNunesdaSilva427 Date: Wed, 11 Jun 2025 15:01:43 -0300 Subject: [PATCH 3/4] Update main.py --- workout_api/main.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/workout_api/main.py b/workout_api/main.py index 07532ee5..07992f7b 100644 --- a/workout_api/main.py +++ b/workout_api/main.py @@ -1,5 +1,8 @@ from fastapi import FastAPI from workout_api.routers import api_router +from fastapi_pagination import add_pagination # ⬅️ Import necessário app = FastAPI(title='WorkoutApi') app.include_router(api_router) + +add_pagination(app) # ⬅️ Ativa a paginação global From 206910979cec34f478a06d2b49522ee8efc2c7c5 Mon Sep 17 00:00:00 2001 From: BrunoNunesdaSilva427 Date: Wed, 11 Jun 2025 15:05:08 -0300 Subject: [PATCH 4/4] Update controller.py --- workout_api/atleta/controller.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/workout_api/atleta/controller.py b/workout_api/atleta/controller.py index 571ee7f8..e4ecdd5a 100644 --- a/workout_api/atleta/controller.py +++ b/workout_api/atleta/controller.py @@ -71,6 +71,7 @@ async def post( detail=f"Já existe um atleta cadastrado com o cpf: {atleta_in.cpf}" ) except Exception: + await db_session.rollback() raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail='Ocorreu um erro ao inserir os dados no banco' @@ -108,7 +109,7 @@ async def query( response_model=AtletaOut, ) async def get(id: UUID4, db_session: DatabaseDependency) -> AtletaOut: - atleta: AtletaOut = ( + atleta = ( await db_session.execute(select(AtletaModel).filter_by(id=id)) ).scalars().first() @@ -128,7 +129,7 @@ async def get(id: UUID4, db_session: DatabaseDependency) -> AtletaOut: response_model=AtletaOut, ) async def patch(id: UUID4, db_session: DatabaseDependency, atleta_up: AtletaUpdate = Body(...)) -> AtletaOut: - atleta: AtletaOut = ( + atleta = ( await db_session.execute(select(AtletaModel).filter_by(id=id)) ).scalars().first() @@ -154,7 +155,7 @@ async def patch(id: UUID4, db_session: DatabaseDependency, atleta_up: AtletaUpda status_code=status.HTTP_204_NO_CONTENT ) async def delete(id: UUID4, db_session: DatabaseDependency) -> None: - atleta: AtletaOut = ( + atleta = ( await db_session.execute(select(AtletaModel).filter_by(id=id)) ).scalars().first() @@ -168,5 +169,4 @@ async def delete(id: UUID4, db_session: DatabaseDependency) -> None: await db_session.commit() -# Adiciona suporte à paginação no router add_pagination(router)