Ошибки Pydantic v2
Ошибка 1: Забыть @classmethod в @field_validator
Симптом: PydanticUserError: 'classmethod' required for field_validator или предупреждение о неправильном использовании валидатора.
Причина: в Pydantic v2 @field_validator требует @classmethod. В v1 @validator мог работать без него.
# НЕПРАВИЛЬНО (v1-стиль, не работает в v2):
@field_validator('date')
def date_must_be_future(cls, v):
...
# ПРАВИЛЬНО (v2):
@field_validator('date')
@classmethod
def date_must_be_future(cls, v: datetime) -> datetime:
...
Ошибка 2: Использование constr/condecimal вместо Annotated
Симптом: ImportError: cannot import name 'constr' from 'pydantic' (в Pydantic v2 эти функции удалены или deprecated).
Причина: constr и condecimal — это функции Pydantic v1. В v2 они не существуют или вызывают предупреждения.
# НЕПРАВИЛЬНО (Pydantic v1):
from pydantic import constr, condecimal
amount: condecimal(gt=0)
tx_type: constr(regex="^(debit|credit)$")
# ПРАВИЛЬНО (Pydantic v2):
from typing import Annotated
from decimal import Decimal
from pydantic import Field
amount: Annotated[Decimal, Field(gt=0)]
tx_type: Annotated[str, Field(pattern=r"^(debit|credit)$")]
Дополнительно: в v2 параметр regex= переименован в pattern=.
Ошибка 3: Использовать class Config вместо ConfigDict
Симптом: предупреждение о deprecation или неожиданное поведение конфигурации модели.
Причина: class Config устарел в Pydantic v2. Используйте model_config = ConfigDict(...).
# НЕПРАВИЛЬНО (Pydantic v1):
class UserProfile(BaseModel):
class Config:
schema_extra = {"example": {...}}
anystr_strip_whitespace = True
# ПРАВИЛЬНО (Pydantic v2):
from pydantic import ConfigDict
class UserProfile(BaseModel):
model_config = ConfigDict(
json_schema_extra={"example": {...}},
str_strip_whitespace=True
)
Ошибки SQLAlchemy 2.x
Ошибка 4: Класс не наследуется от Base
Симптом: Base.metadata.create_all(engine) не создаёт таблицу. При попытке добавить объект: AttributeError: 'Person' object has no attribute '_sa_instance_state'.
Причина: SQLAlchemy узнаёт модели только через наследование от базового класса. Класс без наследования — это просто обычный Python-класс.
# НЕПРАВИЛЬНО:
class Person(): # пустые скобки — не ORM-модель
__tablename__ = 'persons'
...
# ПРАВИЛЬНО:
class Person(Base): # наследуемся от Base
__tablename__ = 'persons'
...
Ошибка 5: Не вызвать create_all перед работой с сессией
Симптом: OperationalError: no such table: users при попытке добавить данные.
Причина: объявление модели в Python не создаёт таблицу в БД. Нужно явно вызвать create_all.
# НЕПРАВИЛЬНО: пропустить create_all
with Session(engine) as session:
session.add(User(name="Alice", age=30)) # OperationalError!
# ПРАВИЛЬНО: сначала create_all
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(User(name="Alice", age=30))
session.commit()
Ошибка 6: Не вызвать session.commit()
Симптом: данные исчезают после закрытия сессии. Запросы возвращают пустые результаты.
Причина: session.add() только помечает объект для добавления в текущей транзакции. Без commit() изменения не сохраняются в БД.
# НЕПРАВИЛЬНО: забыть commit()
with Session(engine) as session:
session.add(User(name="Bob", age=25))
# commit() не вызван — данные потеряны при закрытии сессии
# ПРАВИЛЬНО:
with Session(engine) as session:
session.add(User(name="Bob", age=25))
session.commit() # зафиксировать транзакцию
Ошибка 7: String без длины
Симптом: CompileError при создании таблиц в MySQL/MariaDB. В SQLite работает, в других СУБД — нет.
Причина: MySQL требует явную длину для типа VARCHAR (String). String без аргумента в SQLAlchemy создаёт тип без длины, что не поддерживается MySQL.
# НЕПРАВИЛЬНО (проблема в MySQL):
name: Mapped[str] = mapped_column(String) # нет длины
name = Column(String, nullable=False) # то же
# ПРАВИЛЬНО:
name: Mapped[str] = mapped_column(String(100)) # явная длина
name: Mapped[str] = mapped_column(String(50)) # или другая
Ошибка 8: Не указать back_populates на обеих сторонах связи
Симптом: ArgumentError: Relationship 'User.posts' will copy column posts.user_id to column users.id или неожиданное поведение при обходе связи.
Причина: если back_populates="posts" указан в Post.user, то в User обязательно нужно posts = relationship(..., back_populates="user").
# НЕПРАВИЛЬНО: back_populates только с одной стороны
class User(Base):
posts: Mapped[List["Post"]] = relationship("Post") # нет back_populates
class Post(Base):
user: Mapped["User"] = relationship("User", back_populates="posts") # ошибка!
# ПРАВИЛЬНО: back_populates на обеих сторонах
class User(Base):
posts: Mapped[List["Post"]] = relationship("Post", back_populates="user")
class Post(Base):
user: Mapped["User"] = relationship("User", back_populates="posts")