Я пытаюсь иметь конечную точку, например /services?status=New
status будет либо New, либо Old
Вот мой код:
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from enum import Enum
router = APIRouter()
class ServiceStatusEnum(str, Enum):
new = "New"
old = "Old"
class ServiceStatusQueryParam(BaseModel):
status: ServiceStatusEnum
@router.get("/services")
def get_services(
status: ServiceStatusQueryParam = Query(..., title = "Services", description = "my desc"),
):
pass #my code for handling this route.....
В результате я получаю ошибку, которая, кажется, имеет отношение к этой проблеме здесь
Ошибка говорит AssertionError: Param: status can only be a request body, using Body()
Затем я нашел другое решение, объясненное здесь.
Итак, мой код будет таким:
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from enum import Enum
router = APIRouter()
class ServiceStatusEnum(str, Enum):
new = "New"
old = "Old"
class ServicesQueryParam(BaseModel):
status: ServiceStatusEnum
@router.get("/services")
def get_services(
q: ServicesQueryParam = Depends(),
):
pass #my code for handling this route.....
Работает (и не пойму почему) - но вопрос как и куда добавить описание и заголовок?
Я не совсем понимаю разницу, потому что я новичок в fastapi, но вы, похоже, правы. Я тестировал, и он работает
Как было в вашем первом фрагменте кода, параметр запроса URL теоретически должен быть ?status = {"status":"New"} или что-то в этом роде, потому что вы устанавливаете тип параметра запроса status как вашу модель ServiceStatusQueryParam, которая, в свою очередь, сериализуется в объект JSON. . Принимая во внимание, что вы просто хотите, чтобы ваш запрос был ?status=New, то есть, по сути, строкового типа, но ограничен элементами перечисления.
что, если я хочу выполнить некоторую проверку строки? как бы я это сделал?






Чтобы создать модель Pydantic и использовать ее для определения параметров запроса, вам нужно будет использовать Depends() в параметре вашей конечной точки. Чтобы добавить description, title и т. д. для параметров запроса, вы можете обернуть Query() в Field().
Я также хотел бы отметить, что вместо Literal можно использовать тип Enum, как описано здесь и здесь . Кроме того, если кто-то хочет определить поле List внутри модели Pydantic и использовать его в качестве параметра запроса, ему нужно будет либо реализовать это в отдельном классе зависимостей, как показано здесь и здесь, либо снова заверните Query() в Field(), как показано ниже.
Более того, чтобы выполнить проверку параметров запроса внутри модели Pydnatic, можно сделать это, как обычно, используя Pydantic @validator , как показано здесь , а также здесь и здесь . Обратите внимание, что в этом случае, когда BaseModel используется для параметров запроса, повышение ValueError вызовет Internal Server Error. Следовательно, вы должны вместо этого вызвать HTTPException , когда проверка не удалась, или использовать собственный обработчик исключений для обработки ValueError исключений, как показано в Варианте 2 этого ответа . Помимо @validator, можно также иметь дополнительные проверки для Query параметров, как описано в документации FastAPI (см. также Реализация класса запроса).
В качестве примечания, касающегося определения необязательных параметров, в приведенном ниже примере используется подсказка типа Необязательный (сопровождаемый None в качестве значения по умолчанию в Query) из модуля typing ; однако вы также можете взглянуть на этот ответ и этот ответ, в которых описаны все доступные способы, как это сделать.
from fastapi import FastAPI, Depends, Query, HTTPException
from pydantic import BaseModel, Field, validator
from typing import List, Optional, Literal
from enum import Enum
app = FastAPI()
class Status(str, Enum):
new = 'New'
old = 'Old'
class ServiceStatus(BaseModel):
status: Optional[Status] = Field (Query(..., description='Select service status'))
msg: Optional[str] = Field (Query(None, description='Type something'))
choice: Literal['a', 'b', 'c', 'd'] = Field (Query(..., description='Choose something'))
comments: List[str] = Field (Query(..., description='Add some comments'))
@validator('choice')
def check_choice(cls, v):
if v == 'b':
raise HTTPException(status_code=422, detail='Wrong choice')
return v
@app.get('/status')
def main(status: ServiceStatus = Depends()):
return status
Вы можете прочитать комментарий к исходному вопросу?
и могу ли я также включить Path и выполнить сложную проверку между полями?
предположим, я хотел определенную комбинацию статуса и комментариев. как я могу сделать проверку?
Спасибо. ты прав. на самом деле я уже прошел два курса на udemy про fastapi но все же иногда я не знаю что должен делать разработчик и что не должен делать. Я могу создать конечную точку, но не могу понять, это то, что делают профессионалы или нет, и это то, что создатели fastapi представляют себе, что разработчик делает или нет.
например, теперь, когда вы предоставили этот пример, мне интересно, следует ли мне включать Path и Body в класс ServiceStatus или нет
если бы у нас было services/{service_id}, вы бы добавили service_id: str = Field (Path(..., description='')) под class ServiceStatus(BaseModel) или нет?
Пожалуйста, ознакомьтесь с этим ответом , а также этим ответом и этим ответом (вы также можете найти этот полезным). Пожалуйста, внимательно прочитайте связанные ответы выше, а также любые включенные ссылки.
Что, если я хочу сделать выбор статуса нечувствительным к регистру?
Будущим читателям: чтобы сделать enum значения нечувствительными к регистру, взгляните на этот ответ
Я не понимаю цели
ServiceStatusQueryParam. Почему бы просто не аннотировать параметрstatusвашего маршрута напрямую с помощьюServiceStatusEnum. Это будет работать. Вам действительно нужен весь объект JSON в параметре запроса URL? Мне кажется, это супер съеживается.