Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Обработка ошибок: ValidationError и кастомизация
error_handling

Обработка ошибок: ValidationError и кастомизация

Структура ошибок валидации, извлечение деталей, кастомные сообщения об ошибках.

Обработка ошибок: ValidationError и кастомизация

Понимание структуры ошибок и кастомизация сообщений — ключ к удобному API

#Структура ValidationError

from pydantic import BaseModel, Field, ValidationError class User(BaseModel): username: str = Field(min_length=3) email: str age: int = Field(ge=0, le=150) try: User(username="ab", email="invalid", age=200) except ValidationError as e: print(e) # 3 validation errors for User # username # String should have at least 3 characters [...] # email # value is not a valid email address [...] # age # Input should be less than or equal to 150 [...]

#Методы ValidationError

from pydantic import ValidationError try: User(username="ab", email="invalid", age=200) except ValidationError as e: # errors() — список ошибок errors = e.errors() print(errors) # [ # {'type': 'string_too_short', 'loc': ('username',), # 'msg': 'String should have at least 3 characters', # 'input': 'ab', ...}, # {'type': 'value_error', 'loc': ('email',), # 'msg': 'value is not a valid email address', # 'input': 'invalid', ...}, # {'type': 'less_than_equal', 'loc': ('age',), # 'msg': 'Input should be less than or equal to 150', # 'input': 200, ...} # ] # error_count() — количество ошибок print(e.error_count()) # 3 # title — название модели print(e.title) # "User"

#Структура ошибки

Каждая ошибка в errors() содержит:

{ 'type': 'string_too_short', # тип ошибки 'loc': ('username',), # путь к полю 'msg': 'String should have...', # сообщение 'input': 'ab', # входное значение 'ctx': {'min_length': 3}, # контекст ошибки 'url': '...' # ссылка на документацию }

#Извлечение деталей ошибок

from pydantic import ValidationError def format_validation_error(exc: ValidationError) -> str: """Форматирование ошибки для пользователя""" messages = [] for error in exc.errors(): field = '.'.join(str(loc) for loc in error['loc']) msg = error['msg'] messages.append(f"{field}: {msg}") return '; '.join(messages) try: User(username="ab", email="invalid", age=200) except ValidationError as e: user_message = format_validation_error(e) print(user_message) # username: String should have at least 3 characters; # email: value is not a valid email address; # age: Input should be less than or equal to 150

#Кастомизация сообщений через Field

from pydantic import BaseModel, Field class User(BaseModel): username: str = Field( min_length=3, max_length=20, description="Имя пользователя" ) # Кастомные сообщения через json_schema_extra # (работает для JSON Schema, не для валидации)

#Кастомизация через валидаторы

from pydantic import BaseModel, Field, field_validator from typing import Union class User(BaseModel): username: str = Field(min_length=3) email: str age: int @field_validator('username') @classmethod def validate_username(cls, v: str) -> str: if not v.isalnum(): raise ValueError('Username должен содержать только буквы и цифры') return v @field_validator('email') @classmethod def validate_email(cls, v: str) -> str: if '@' not in v: raise ValueError('Неверный формат email') if not v.endswith(('.com', '.org', '.net', '.ru')): raise ValueError('Недопустимый домен email') return v @field_validator('age') @classmethod def validate_age(cls, v: int) -> int: if v < 0: raise ValueError('Возраст не может быть отрицательным') if v > 150: raise ValueError('Возраст не может быть больше 150') return v try: User(username="ab!", email="invalid", age=-5) except ValidationError as e: for error in e.errors(): print(f"{error['loc'][0]}: {error['msg']}") # username: Username должен содержать только буквы и цифры # email: Неверный формат email # age: Возраст не может быть отрицательным

#Типы ошибок Pydantic

Распространённые типы ошибок:

# Типы для строк 'string_too_short' # min_length 'string_too_long' # max_length 'string_pattern_mismatch' # pattern # Типы для чисел 'greater_than' # gt 'greater_than_equal' # ge 'less_than' # lt 'less_than_equal' # le 'multiple_of' # multiple_of # Типы для коллекций 'too_short' # min_length для list/set 'too_long' # max_length для list/set # Типы для моделей 'missing' # обязательное поле отсутствует 'extra_forbidden' # лишнее поле при extra='forbid' # Типы для Union 'union_tag_invalid' # неверный тег дискриминатора 'union_tag_not_found' # поле дискриминатора отсутствует

#Обработка конкретных типов ошибок

from pydantic import ValidationError def handle_validation_error(exc: ValidationError) -> dict: """Обработка ошибок по типам""" result = {'errors': [], 'warnings': []} for error in exc.errors(): error_type = error['type'] field = error['loc'][0] msg = error['msg'] if error_type == 'missing': result['errors'].append(f"{field}: обязательное поле") elif error_type == 'string_too_short': result['errors'].append(f"{field}: слишком короткое значение") elif error_type == 'greater_than_equal': result['errors'].append(f"{field}: значение слишком мало") elif error_type == 'less_than_equal': result['errors'].append(f"{field}: значение слишком велико") else: result['errors'].append(f"{field}: {msg}") return result try: User(username="ab", email="invalid", age=200) except ValidationError as e: handled = handle_validation_error(e) print(handed)

#Глобальный обработчик ошибок (FastAPI)

from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from pydantic import ValidationError app = FastAPI() @app.exception_handler(ValidationError) async def validation_exception_handler( request: Request, exc: ValidationError ): errors = [] for error in exc.errors(): errors.append({ 'field': '.'.join(str(loc) for loc in error['loc']), 'message': error['msg'], 'type': error['type'] }) return JSONResponse( status_code=422, content={ 'success': False, 'error': 'validation_error', 'errors': errors } )

#Валидация с возвратом ошибок

from pydantic import BaseModel, ValidationError from typing import Tuple, Optional def safe_validate(model_class, data: dict) -> Tuple[Optional[BaseModel], Optional[str]]: """Безопасная валидация с возвратом ошибки""" try: instance = model_class(**data) return instance, None except ValidationError as e: error_msg = '; '.join( f"{err['loc'][0]}: {err['msg']}" for err in e.errors() ) return None, error_msg # Использование user, error = safe_validate(User, {'username': 'ab', 'email': 'invalid', 'age': 200}) if error: print(f"Ошибка: {error}") else: print(f"Успешно: {user}")

#Логи ошибок

import logging from pydantic import ValidationError logger = logging.getLogger(__name__) def log_validation_error(exc: ValidationError, context: str = ""): """Логирование ошибки валидации""" logger.warning( f"Validation error in {context}: {exc.error_count()} errors", extra={ 'model': exc.title, 'errors': [ {'field': '.'.join(str(loc) for loc in err['loc']), 'type': err['type'], 'msg': err['msg']} for err in exc.errors() ] } ) try: User(username="ab", email="invalid", age=200) except ValidationError as e: log_validation_error(e, context="user_creation") raise

#Мини-проект: Система валидации форм

Создайте систему валидации с кастомными сообщениями:

from pydantic import BaseModel, Field, field_validator, ValidationError from typing import Dict, List, Optional from enum import Enum class ErrorCode(str, Enum): REQUIRED = "required" TOO_SHORT = "too_short" TOO_LONG = "too_long" INVALID_FORMAT = "invalid_format" OUT_OF_RANGE = "out_of_range" class ValidationResult(BaseModel): success: bool errors: Dict[str, str] = {} def add_error(self, field: str, message: str): self.errors[field] = message @property def is_valid(self) -> bool: return len(self.errors) == 0 class ValidatedModel(BaseModel): """Базовый класс для моделей с кастомными сообщениями""" @classmethod def validate_with_messages(cls, data: dict) -> ValidationResult: """Валидация с кастомными сообщениями""" result = ValidationResult(success=True) try: cls(**data) except ValidationError as e: result.success = False for error in e.errors(): field = '.'.join(str(loc) for loc in error['loc']) # Кастомизация сообщений по типу ошибки if error['type'] == 'missing': result.add_error(field, f"Поле '{field}' обязательно") elif error['type'] == 'string_too_short': result.add_error(field, f"Поле '{field}' слишком короткое") elif error['type'] == 'string_too_long': result.add_error(field, f"Поле '{field}' слишком длинное") else: result.add_error(field, error['msg']) return result # Пример использования: class UserForm(ValidatedModel): username: str = Field(min_length=3, max_length=20) email: str age: int = Field(ge=0, le=150) result = UserForm.validate_with_messages( {'username': 'ab', 'email': 'invalid', 'age': 200} ) print(result.is_valid) # False print(result.errors) # {'username': '...', 'email': '...', 'age': '...'}

Далее: Производительность: оптимизация валидации