You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastAPI中实现多可选参数互斥(仅允许传其一)

实现互斥查询参数的几种替代方式

首先要指出你现有代码的一个隐患:它只处理了单个参数存在的情况,但没有校验多个参数同时传入的非法场景。比如用户同时传guid和code时,代码会直接返回guid对应的结果,这违反了“仅能传入一个参数”的要求。下面是几种更严谨的实现方式:

方案1:先统计非空参数数量做校验

先统计三个参数里非空的数量,确保只有一个参数被传入,再处理各自的逻辑:

from fastapi import status
from fastapi.responses import PlainTextResponse
from typing import Optional, Union, List
from your_module import Locations, router

@router.get("/api/locations")
def get_functional_locations(
    guid: Optional[str] = None,
    code: Optional[str] = None,
    path: Optional[str] = None,
) -> Union[List[Locations], PlainTextResponse]:
    # 统计非空参数的数量
    non_empty_count = sum(1 for param in [guid, code, path] if param is not None)
    
    if non_empty_count != 1:
        return PlainTextResponse(
            "必须且只能传入guid、code、path中的一个参数",
            status_code=status.HTTP_400_BAD_REQUEST
        )
    
    if guid:
        return ...  # 处理guid逻辑
    elif path:
        return ...  # 处理path逻辑
    elif code:
        return ...  # 处理code逻辑

方案2:用自定义依赖封装校验逻辑

把互斥参数的校验逻辑抽离成独立依赖,既保证代码整洁,也方便后续复用:

from fastapi import Depends, Query, HTTPException
from fastapi import status
from typing import Optional, Union, List, Tuple
from your_module import Locations, router

def get_location_query_param(
    guid: Optional[str] = Query(None),
    code: Optional[str] = Query(None),
    path: Optional[str] = Query(None),
) -> Tuple[str, str]:
    # 整理参数键值对,过滤空值
    param_map = {
        "guid": guid,
        "code": code,
        "path": path
    }
    valid_params = [(key, value) for key, value in param_map.items() if value is not None]
    
    if len(valid_params) != 1:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="必须且只能传入guid、code、path中的一个参数"
        )
    # 返回(参数类型, 参数值)
    return valid_params[0]

@router.get("/api/locations")
def get_functional_locations(
    param_info: Tuple[str, str] = Depends(get_location_query_param)
) -> Union[List[Locations], PlainTextResponse]:
    param_type, param_value = param_info
    
    if param_type == "guid":
        return ...  # 处理guid逻辑
    elif param_type == "path":
        return ...  # 处理path逻辑
    elif param_type == "code":
        return ...  # 处理code逻辑

方案3:用Pydantic模型做校验

借助Pydantic的validator来实现互斥参数的校验,适合参数逻辑更复杂的场景:

from fastapi import Depends, HTTPException
from fastapi import status
from pydantic import BaseModel, validator
from typing import Optional, Union, List
from your_module import Locations, router

class LocationQueryParams(BaseModel):
    guid: Optional[str] = None
    code: Optional[str] = None
    path: Optional[str] = None

    @validator("*", pre=True, always=True)
    def check_single_param(cls, v, values):
        # 统计非空参数数量
        non_empty = sum(1 for val in values.values() if val is not None)
        # 如果当前参数非空且已经有其他非空参数,抛出错误
        if v is not None and non_empty > 0:
            raise ValueError("只能传入guid、code、path中的一个参数")
        return v

@router.get("/api/locations")
def get_functional_locations(
    params: LocationQueryParams = Depends()
) -> Union[List[Locations], PlainTextResponse]:
    if params.guid:
        return ...  # 处理guid逻辑
    elif params.path:
        return ...  # 处理path逻辑
    elif params.code:
        return ...  # 处理code逻辑
    else:
        return PlainTextResponse(
            "必须传入guid、code、path中的一个参数",
            status_code=status.HTTP_400_BAD_REQUEST
        )

这几种方案都能严格保证“仅传入一个参数”的要求,避免了现有代码的漏洞。

内容的提问来源于stack exchange,提问作者kaiserm99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:27:40