В FastAPI на базе Pydantic Field позволяет задавать дополнительные настройки для полей моделей. Это поднимает валидацию данных на новую высоту. С помощью Field можно:
- Настраивать значения по умолчанию для полей.
- Ограничивать возможные значения (например, минимальная длина строки, диапазон чисел).
- Добавлять метаданные (описания, примеры).
- Указывать дополнительные условия валидации.
Если задуматься, то Field — это как чек-лист правил для каждого поля. У каждого программиста есть своя вариация "что проверить перед сдачей проекта", так и у нашего API есть строгая проверка данных через Field.
Простая аналогия: если бы наши данные были гостем на вечеринке, то Field — это строгий дядя-секьюрити, который проверяет, одет ли гость в приличную одежду, есть ли у него приглашение и, конечно, не слишком ли громкий у него смех.
Синтаксис Field
Чтобы использовать Field, просто импортируем его из pydantic и добавляем в описание модели:
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=50, description="Имя пользователя")
age: int = Field(..., ge=18, le=150, description="Возраст пользователя (должен быть от 18 до 150)")
Разберём параметры:
...(Ellipsis) означает, что поле обязательно.min_lengthиmax_lengthзадают минимальную и максимальную длину строки.ge(greater or equal) иle(less or equal) задают диапазон значений для числа.descriptionдобавляет описание для документации.
Как использовать Field в реальных проектах?
Давайте создадим модель для регистрации пользователей. Параметры должны валидироваться следующим образом:
- Имя пользователя (
username) — должно быть обязательным, длина от 3 до 50 символов. - Электронная почта (
email) — строка, которая обязательно должна быть валидным email. - Возраст (
age) — обязателен, от 18 до 120 лет. - Описание (
bio) — необязательное поле, не длиннее 300 символов.
Пример кода:
from pydantic import BaseModel, Field, EmailStr
class RegisterUser(BaseModel):
username: str = Field(..., min_length=3, max_length=50, description="Имя пользователя")
email: EmailStr = Field(..., description="Электронная почта пользователя")
age: int = Field(..., ge=18, le=120, description="Возраст пользователя")
bio: str = Field(None, max_length=300, description="Краткое описание о пользователе")
# Пример использования:
input_data = {
"username": "JohnDoe",
"email": "john.doe@example.com",
"age": 25,
"bio": "I love Python and FastAPI!"
}
user = RegisterUser(**input_data)
print(user)
Что происходит при валидации?
Если данные соответствуют требованиям, Pydantic создаёт объект модели на основе входных данных. Если какой-то параметр не проходит проверку, будет выброшено исключение ValidationError с подробным описанием, что пошло не так.
Например, если передать в age отрицательное значение:
input_data = {
"username": "JohnDoe",
"email": "john.doe@example.com",
"age": -5, # Это явно не ок!
"bio": "I love Python and FastAPI!"
}
try:
user = RegisterUser(**input_data)
except ValidationError as e:
print(e.json())
Получим:
[
{
"loc": ["age"],
"msg": "ensure this value is greater than or equal to 18",
"type": "value_error.number.not_ge",
"ctx": {"limit_value": 18}
}
]
Настройка значений по умолчанию
Если поле не обязательно, можно указать значение по умолчанию, которое автоматически подставится при отсутствии данных:
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
age: int = Field(30, ge=18, le=120) # Значение по умолчанию — 30
bio: str = Field("No bio provided.", max_length=300) # Дефолтное описание
# Пример:
input_data = {
"username": "JaneDoe"
}
user = User(**input_data)
print(user)
# Вывод: username='JaneDoe' age=30 bio='No bio provided.'
Описание полей для OpenAPI документации
FastAPI автоматически использует описания, указанные в Field, чтобы дополнить документацию. Если открыть автоматически сгенерированную Swagger UI, можно увидеть красивые описания всех полей:
from fastapi import FastAPI
app = FastAPI()
@app.post("/users/")
async def create_user(user: RegisterUser):
return user
Теперь, зайдя на /docs, вы увидите каждое наше описание, примеры и ограничения. Презентабельно и профессионально!
Дополнительные параметры
alias— задаёт альтернативное название поля (например, для совместимости с внешними API).example— задаёт пример значения (отображается в Swagger UI).regex— позволяет указать регулярное выражение для проверки данных.
Пример использования alias и regex:
Попробуем создать модель, которая валидирует телефонные номера:
class PhoneNumber(BaseModel):
phone: str = Field(..., regex=r"^\+\d{1,3}-\d{3}-\d{4}$", alias="phone_number", example="+123-456-7890")
# Пример:
input_data = {"phone_number": "+123-456-7890"}
phone = PhoneNumber(**input_data)
print(phone)
Модель проверит, что телефонный номер соответствует формату +XXX-XXX-XXXX. Если строка не соответствует регулярному выражению, будет выдана ошибка.
Типичные ошибки при работе с Field
Иногда разработчики сталкиваются с такими проблемами:
- Ошибка с обязательными полями. Если забыть указать значение для обязательного поля (с
...), Pydantic броситValidationError. - Неверные типы данных. Если передать строку вместо числа или наоборот, произойдёт ошибка валидации. Pydantic проверяет типы данных с особой строгостью.
- Игнорирование метаданных. Некоторые новички не указывают описания, примеры или удобные ограничения, что затрудняет поддержку кода в будущем.
Практическая задача
Давайте напишем модель для добавления товаров в интернет-магазин. У товара должно быть:
- Название (
name), обязательное, до 100 символов. - Цена (
price), обязательное поле, положительное число. - Категория (
category), строка, значение по умолчанию — "general". - Описание (
description), необязательное поле, не более 500 символов.
Реализуйте эндпоинт /products/, который принимает эту модель и возвращает сохранённые данные.
Решение:
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Product(BaseModel):
name: str = Field(..., max_length=100, description="Название товара")
price: float = Field(..., gt=0, description="Цена товара (должна быть положительной)")
category: str = Field("general", description="Категория товара")
description: str = Field(None, max_length=500, description="Описание товара")
@app.post("/products/")
async def create_product(product: Product):
return {"msg": "Товар успешно добавлен!", "product": product}
Итак, теперь вы можете настраивать поля в ваших моделях как профессионал. Ваш код стал не только надёжнее, но и элегантнее. Мы продолжаем! 😉
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ