← Назад к вопросам

Что такое базовая модель?

2.0 Middle🔥 141 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Базовая модель (Base Model)

Базовая модель (Base Model, или базовый класс) — это родительский класс, от которого наследуются другие классы. Базовая модель определяет общие свойства и методы, которые используются всеми дочерними классами. Это фундаментальная концепция объектно-ориентированного программирования (ООП) и архитектуры приложений.

Что такое базовая модель?

# Без базовой модели — дублирование кода
class User:
    def __init__(self, id, name):
        self.id = id
        self.name = name
    
    def save(self):
        print(f"Saving user {self.name}")
    
    def delete(self):
        print(f"Deleting user {self.name}")

class Product:
    def __init__(self, id, name):
        self.id = id
        self.name = name
    
    def save(self):
        print(f"Saving product {self.name}")
    
    def delete(self):
        print(f"Deleting product {self.name}")

# Много дублирования!

Решение: базовая модель

# Один раз определяем общую логику
class BaseModel:
    def __init__(self, id, name):
        self.id = id
        self.name = name
    
    def save(self):
        print(f"Saving {self.__class__.__name__} {self.name}")
    
    def delete(self):
        print(f"Deleting {self.__class__.__name__} {self.name}")

# Дочерние классы наследуют базовую логику
class User(BaseModel):
    pass

class Product(BaseModel):
    pass

# Используем
user = User(1, "Alice")
user.save()  # Saving User Alice

product = Product(2, "Laptop")
product.delete()  # Deleting Product Laptop

Pydantic BaseModel

В современном Python часто используется Pydantic BaseModel для валидации данных:

from pydantic import BaseModel, EmailStr, Field
from typing import Optional

# Базовая модель в Pydantic
class User(BaseModel):
    id: int
    name: str
    email: EmailStr
    age: Optional[int] = None

# Автоматическая валидация
user = User(
    id=1,
    name="Alice",
    email="alice@example.com",
    age=30
)

# JSON сериализация
print(user.model_dump())  # {'id': 1, 'name': 'Alice', ...}
print(user.model_dump_json())  # JSON строка

# Валидация при создании
try:
    invalid_user = User(
        id=1,
        name="Alice",
        email="not-an-email",  # Ошибка!
        age=30
    )
except ValueError as e:
    print(f"Validation error: {e}")

Пример: ORM модели

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, Integer, DateTime, func
from datetime import datetime, UTC

# Базовая модель для всех таблиц
class Base(DeclarativeBase):
    pass

# Общие поля для всех моделей
class TimestampedModel(Base):
    __abstract__ = True  # Не создаёт таблицу, только наследуется
    
    id: Mapped[int] = mapped_column(primary_key=True)
    created_at: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC))
    updated_at: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC), onupdate=func.now())

# Дочерние модели
class User(TimestampedModel):
    __tablename__ = 'users'
    
    name: Mapped[str] = mapped_column(String(100))
    email: Mapped[str] = mapped_column(String(100), unique=True)

class Product(TimestampedModel):
    __tablename__ = 'products'
    
    title: Mapped[str] = mapped_column(String(200))
    price: Mapped[float]

# Все модели имеют id, created_at, updated_at автоматически

Пример: Domain Model (DDD)

from datetime import datetime
from enum import Enum
from uuid import UUID

# Базовая модель для всех domain сущностей
class DomainModel:
    def __init__(self, id: UUID):
        self.id = id
        self.version = 0  # Для optimistic locking
        self.created_at = datetime.now()
    
    def mark_as_changed(self):
        self.version += 1

class UserStatus(Enum):
    ACTIVE = "active"
    BLOCKED = "blocked"
    DELETED = "deleted"

class User(DomainModel):
    def __init__(self, id: UUID, email: str, name: str):
        super().__init__(id)
        self.email = email
        self.name = name
        self.status = UserStatus.ACTIVE
        self.orders = []
    
    def block(self):
        self.status = UserStatus.BLOCKED
        self.mark_as_changed()
    
    def add_order(self, order):
        self.orders.append(order)
        self.mark_as_changed()

class Order(DomainModel):
    def __init__(self, id: UUID, user_id: UUID, total: float):
        super().__init__(id)
        self.user_id = user_id
        self.total = total
        self.status = "pending"
    
    def complete(self):
        self.status = "completed"
        self.mark_as_changed()

Пример: API Response Model

from pydantic import BaseModel, ConfigDict
from typing import Generic, TypeVar

T = TypeVar('T')

# Базовая модель для всех API ответов
class BaseResponse(BaseModel):
    success: bool
    message: str
    model_config = ConfigDict(from_attributes=True)

class PaginatedResponse(BaseResponse, Generic[T]):
    data: list[T]
    total: int
    page: int
    per_page: int
    total_pages: int

# Использование
class UserDTO(BaseModel):
    id: int
    name: str
    email: str

users_response = PaginatedResponse[
    response = PaginatedResponse[
        UserDTO
    ](
        success=True,
        message="Users fetched successfully",
        data=[
            UserDTO(id=1, name="Alice", email="alice@example.com"),
            UserDTO(id=2, name="Bob", email="bob@example.com"),
        ],
        total=2,
        page=1,
        per_page=10,
        total_pages=1
    )

Пример: Repository Pattern

from abc import ABC, abstractmethod
from typing import Generic, TypeVar, List

T = TypeVar('T')
ID = TypeVar('ID')

# Базовая модель для всех репозиториев
class BaseRepository(ABC, Generic[T, ID]):
    @abstractmethod
    def get(self, id: ID) -> T:
        """Get entity by id"""
        pass
    
    @abstractmethod
    def get_all(self) -> List[T]:
        """Get all entities"""
        pass
    
    @abstractmethod
    def save(self, entity: T) -> T:
        """Save entity"""
        pass
    
    @abstractmethod
    def delete(self, id: ID) -> None:
        """Delete entity"""
        pass

# Реализация для User
class UserRepository(BaseRepository[User, int]):
    def __init__(self, db):
        self.db = db
    
    def get(self, id: int) -> User:
        return self.db.query(User).filter(User.id == id).first()
    
    def get_all(self) -> List[User]:
        return self.db.query(User).all()
    
    def save(self, entity: User) -> User:
        self.db.add(entity)
        self.db.commit()
        return entity
    
    def delete(self, id: int) -> None:
        user = self.get(id)
        self.db.delete(user)
        self.db.commit()

Лучшие практики базовых моделей

1. DRY принцип (Don't Repeat Yourself)

# ❌ Плохо — дублирование
class User:
    def validate(self): pass
    def to_dict(self): pass

class Product:
    def validate(self): pass
    def to_dict(self): pass

# ✅ Хорошо — одна базовая модель
class BaseModel:
    def validate(self): pass
    def to_dict(self): pass

2. Не переусложняй

# ❌ Плохо — слишком абстрактно
class VeryGenericBase:
    def do_something_abstract(self): pass
    def do_another_thing(self): pass

# ✅ Хорошо — конкретные методы
class Model:
    def validate(self): pass
    def save(self): pass

3. Используй composition вместо наследования

# ❌ Плохо — глубокое наследование
class A:
    pass

class B(A):
    pass

class C(B):
    pass

# ✅ Хорошо — composition
class Timestamps:
    created_at: datetime
    updated_at: datetime

class Model:
    timestamps: Timestamps

Резюме

Базовая модель — это родительский класс, определяющий общую функциональность:

  1. Что это: класс, от которого наследуются другие классы
  2. Зачем: избежать дублирования кода, определить общий интерфейс
  3. Примеры: Pydantic BaseModel, SQLAlchemy Base, Abstract Base Classes
  4. В архитектуре: используется в DDD, Repository Pattern, API Design
  5. Правило: SOLID принципы, не переусложняй, используй composition

Хорошо спроектированные базовые модели делают код чище, понятнее и проще в поддержке.

Что такое базовая модель? | PrepBro