我正在使用 FastAPI 为资源创建 2 个 GET 方法。我希望通过 2 种方式获得
student
:通过 student
或通过 student_id
。问题是,我最初创建了 2 个端点,如下
student_name
问题是端点名称相互冲突,都是
@app.get("/student/{student_name}", response_model=schemas.Student, status_code=200)
def get_student_by_name(student_name: str, db: Session = Depends(get_db)):
db_student = crud.get_student_by_name(db, student_name)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
@app.get("/student/{student_id}", response_model=schemas.Student, status_code=200)
def get_student_by_id(student_id: int, db: Session = Depends(get_db)):
db_student = crud.get_student_by_id(db, student_id)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
后跟一个参数,并且只有其中一个可以工作 - 在这种情况下只有
/student
,因为它是在前面定义的。因此,我想出了这个简单的解决方法,通过在端点名称中添加更多内容:/student/{student_name}
我将
@app.get("/student/{student_name}", response_model=schemas.Student, status_code=200)
def get_student_by_name(student_name: str, db: Session = Depends(get_db)):
db_student = crud.get_student_by_name(db, student_name)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
@app.get("/student/byid/{student_id}", response_model=schemas.Student, status_code=200)
def get_student_by_id(student_id: int, db: Session = Depends(get_db)):
db_student = crud.get_student_by_id(db, student_id)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
添加到
/byid
方法的端点名称中。虽然两个端点现在都可以工作,但我想知道这是否被认为是一个好的做法?当需要使用单个路径参数查询一个资源以区分端点名称时,最佳实践是什么?@app.get("/student/{student_name:str}", response_model=schemas.Student, status_code=200)
def get_student_by_name(student_name: str, db: Session = Depends(get_db)):
...
@app.get("/student/{student_id:int}", response_model=schemas.Student, status_code=200)
def get_student_by_id(student_id: int, db: Session = Depends(get_db)):
...
有了这个,你的代码将对未来的更改更加开放,我只会在按 id 搜索时使用 url 参数,任何其他搜索条件都可以使用查询参数作为过滤器参数处理
如果我想确保与要移植到 FastAPI 的 Web 框架的兼容性,并且它显示了原始行为,那么我可以通过一种方法来复制它。
@app.get("/student/{student_id}", response_model=schemas.Student, status_code=200)
def get_student(student_id: str, db: Session = Depends(get_db)):
db_student = crud.get_student_by_id(db, student_id)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
# use search criterias as query params
@app.get("/student/", response_model=List[schemas.Student], status_code=200)
def get_students(student_name: string = None, db: Session = Depends(get_db)):
# Query inside your crud file
query = db.query(Student)
if student_name:
# if you want to search similar items
query = query.filter(Student.name.like(f"%{student_name}%"))
# if you want to search an exact match
query = query.filter(Student.name == student_name)
return query.all()
FastAPI 强调输入和文档,这对我来说是有意义的,相同的路径前缀应该智能地路由到更具体的、可转换的,特别是如果更具体的优先的话。
如果我可以放弃更强大的文档和验证,我可以像这样涵盖两个基础:
@app.get("/student/{student_id}",
response_model=schemas.Student,
status_code=200)
def get_student_by_id(
student_id: int = Path(
title="The ID of the student to get"),
db: Session = Depends(get_db)):
db_student = crud.get_student_by_id(db, student_id)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
...
@app.get("/student/{student_name}",
response_model=schemas.Student,
status_code=200)
def get_student_by_name(
student_name: str,
db: Session = Depends(get_db)):
db_student = crud.get_student_by_name(db, student_name)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
https://fastapi.tiangolo.com/tutorial/path-params/#path-convertor
用于验证参数是否为 int
或学生姓名的现有逻辑,然后验证这些逻辑或返回适当的错误。我看你已经有了这个逻辑,所以这不是最大的缺点。
我最初经常使用这种方法。了解了所包含的 OpenAPI 文档的价值后,我更喜欢单独的功能。有时维护网站链接会更好。例如,WordPress 可以同时在
@app.get("/student/{student_name_or_id}",
response_model=schemas.Student,
status_code=200)
async def get_student(
student_name_or_id: str = Path(
title="The ID or name of the student to get"),
db: Session = Depends(get_db)):
if student_name_or_id.isdigit():
db_student = crud.get_student_by_id(db, int(student_name_or_id))
else:
db_student = crud.get_student_by_name(db, student_name_or_id)
if db_student is None:
raise HTTPException(status_code=404, detail="Student not found")
return db_student
和 int
提供页面,一个使用日期,另一个使用类别和 slug。
您可以使用查询参数来仅使用一个路径来区分student_id和student_name,这是达到相同目的的更简洁的方式,例如:
然后,您可以通过运行 if 语句来根据查询参数提供请求的数据,如下所示:
/python/faster-fastapi
希望这有帮助