【发布时间】:2022-07-22 06:22:31
【问题描述】:
假设我有两个实体,Users 和 Councils,以及一个 M2M 关联表 UserCouncils。 Users 可以从 Councils 添加/删除,并且只有管理员可以这样做(在 UserCouncil 关系中的 role 属性中定义)。
现在,在为/councils/{council_id}/remove 创建端点时,我面临着在操作前检查多个约束的问题,例如:
@router.delete("/{council_id}/remove", response_model=responses.CouncilDetail)
def remove_user_from_council(
council_id: int | UUID = Path(...),
*,
user_in: schemas.CouncilUser,
db: Session = Depends(get_db),
current_user: Users = Depends(get_current_user),
council: Councils = Depends(council_id_dep),
) -> dict[str, Any]:
"""
DELETE /councils/:id/remove (auth)
remove user with `user_in` from council
current user must be ADMIN of council
"""
# check if input user exists
if not Users.get(db=db, id=user_in.user_id):
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User not found"
)
if not UserCouncil.get(db=db, user_id=user_in.user_id, council_id=council.id):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Cannot delete user who is not part of council",
)
# check if current user exists in council
if not (
relation := UserCouncil.get(
db=db, user_id=current_user.id, council_id=council.id
)
):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Current user not part of council",
)
# check if current user is Admin
if relation.role != Roles.ADMIN:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="Unauthorized"
)
elif current_user.id == user_in.user_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Admin cannot delete themselves",
)
else:
updated_users = council.remove_member(db=db, user_id=user_in.user_id)
result = {"council": council, "users": updated_users}
return result
这些检查是不言自明的。但是,这会在端点定义中添加大量代码。端点定义通常应该是简约的吗?我可以将所有这些检查包装在 Councils crud 方法中(即 council.remove_member()),但这意味着在 crud 类中添加 HTTPExceptions,我不想这样做。
解决此类情况的一般最佳做法是什么,我可以在哪里阅读更多相关信息?任何形式的帮助将不胜感激。
谢谢。
【问题讨论】:
-
为什么必须使用获取当前用户的依赖项检查用户是否存在之后?该依赖项应验证用户是否存在并且是有效用户;获取委员会的代码也是如此;让它依赖于用户和委员会 ID,并在你的依赖中解决这个问题。您还可以将该依赖项设为
council_with_current_user_as_admin,以便将其全部隐藏在依赖层后面。您的视图变得非常有效和简洁,并且您的依赖项可以很容易地被重用来组合不同的需求。 -
检查用户是否存在是针对输入用户
user_in。current_user只解析头部以获取当前登录的用户。但你是对的。关系依赖会清除混乱。
标签: python rest design-patterns sqlalchemy fastapi