Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
С какими ORM работал?
В своей карьере работал с несколькими популярными ORM для Python, каждая из которых имеет свои сильные стороны и применение.
1. SQLAlchemy (2.0+) — мой основной выбор
Самая мощная и гибкая ORM в Python. Работал как с Core, так и с ORM слоем.
Основное применение:
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base, Session, relationship
from datetime import datetime
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(120), unique=True, nullable=False)
created_at = Column(DateTime, default=lambda: datetime.now(UTC))
posts = relationship('Post', back_populates='author', cascade='all, delete-orphan')
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String(255), nullable=False)
content = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
created_at = Column(DateTime, default=lambda: datetime.now(UTC))
author = relationship('User', back_populates='posts')
engine = create_engine('postgresql://user:pass@localhost/dbname')
Base.metadata.create_all(engine)
# Использование
with Session(engine) as session:
# Create
user = User(username='alice', email='alice@example.com')
session.add(user)
session.commit()
# Read
user = session.query(User).filter(User.username == 'alice').first()
# Update
user.email = 'alice_new@example.com'
session.commit()
# Delete
session.delete(user)
session.commit()
Преимущества:
- Гибкость: можно писать как высокоуровневый ORM код, так и raw SQL
- Мощные relationships и lazy loading strategies
- Встроенная поддержка transactions и session management
- Отличная документация
- Поддержка множества БД (PostgreSQL, MySQL, SQLite, Oracle и т.д.)
Недостатки:
- Крутая кривая обучения
- Иногда медленнее простых решений
- Может быть overkill для простых приложений
2. Django ORM — для полного фреймворка
Использовал для проектов на Django, где ORM интегрирована в фреймворк.
from django.db import models
from django.utils import timezone
class User(models.Model):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.username
class Post(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
# Использование (в views)
from django.shortcuts import get_object_or_404
def user_posts(request, user_id):
user = get_object_or_404(User, id=user_id)
posts = user.posts.all() # QuerySet (ленивый)
# Фильтрация
posts = posts.filter(created_at__year=2024)
# Агрегация
post_count = posts.count()
# Аннотация
from django.db.models import Count
users_with_counts = User.objects.annotate(post_count=Count('posts'))
return render(request, 'posts.html', {'posts': posts})
Преимущества:
- Простая и интуитивная
- Отличная интеграция с Django админкой
- Встроенная миграции (Django Migrations)
- Быстро писать для стандартных задач
Недостатки:
- Тесно связана с Django (сложно использовать отдельно)
- Менее гибкая, чем SQLAlchemy
- Сложнее писать сложные queries
3. Peewee — лёгкая ORM
Использовал для небольших проектов, где нужна простая ORM без Django.
from peewee import SqliteDatabase, Model, CharField, ForeignKeyField, DateTimeField
from datetime import datetime
db = SqliteDatabase('my_app.db')
class BaseModel(Model):
class Meta:
database = db
class User(BaseModel):
username = CharField(unique=True)
email = CharField(unique=True)
created_at = DateTimeField(default=datetime.now)
class Post(BaseModel):
title = CharField()
content = CharField()
author = ForeignKeyField(User, backref='posts')
created_at = DateTimeField(default=datetime.now)
db.create_tables([User, Post])
# Использование
user = User.create(username='bob', email='bob@example.com')
post = Post.create(title='Hello', content='World', author=user)
# Query
user_posts = Post.select().where(Post.author == user)
for post in user_posts:
print(post.title)
Преимущества:
- Очень простая и лёгкая
- Низкий overhead
- Идеально для небольших проектов
- Хорошо работает с SQLite
Недостатки:
- Менее мощная, чем SQLAlchemy
- Меньшее сообщество
- Сложнее для сложных relationships
4. Tortoise ORM — для async приложений
Использовал для асинхронных проектов на FastAPI/aiohttp.
from tortoise import fields, run_async
from tortoise.models import Model
from tortoise.queryset import QuerySet
class User(Model):
id = fields.IntField(pk=True)
username = fields.CharField(max_length=50, unique=True)
email = fields.CharField(max_length=120, unique=True)
created_at = fields.DatetimeField(auto_now_add=True)
posts: QuerySet # type hint
class Meta:
table = "users"
class Post(Model):
id = fields.IntField(pk=True)
title = fields.CharField(max_length=255)
content = fields.TextField()
author: fields.ForeignKeyRelation[User] = fields.ForeignKeyField(
'models.User', related_name='posts', on_delete=fields.CASCADE
)
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "posts"
# Async использование
async def get_user_posts(user_id: int):
user = await User.get(id=user_id)
posts = await user.posts.all()
return posts
async def main():
await Tortoise.init(
db_url='sqlite://:memory:',
modules={'models': ['__main__']}
)
await Tortoise.generate_schemas()
# CRUD
user = await User.create(username='alice', email='alice@example.com')
await Post.create(title='Hello', content='World', author=user)
posts = await get_user_posts(user.id)
for post in posts:
print(post.title)
if __name__ == '__main__':
run_async(main())
Преимущества:
- Native async/await поддержка
- Отличная для FastAPI
- Асинхронные миграции
Недостатки:
- Молодой проект
- Меньше сообщества
- Может быть менее стабильным
5. SQLModel — новый подход
Экспериментировал с SQLModel (комбо Pydantic + SQLAlchemy) для FastAPI.
from sqlmodel import SQLModel, Field, create_engine, Session, select
from typing import Optional, List
class User(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
username: str = Field(unique=True, index=True)
email: str = Field(unique=True, index=True)
posts: List['Post'] = []
class Post(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
title: str
content: str
user_id: int = Field(foreign_key='user.id')
author: Optional[User] = None
engine = create_engine('sqlite:///database.db')
SQLModel.metadata.create_all(engine)
# Использование
def create_user(user: User):
with Session(engine) as session:
session.add(user)
session.commit()
session.refresh(user)
return user
def get_users():
with Session(engine) as session:
statement = select(User)
return session.exec(statement).all()
Преимущества:
- Единая модель для БД и API
- Отличная типизация
- Автоматическая валидация Pydantic
- Идеально для FastAPI
Недостатки:
- Ещё молодой проект
- Меньше функциональности, чем SQLAlchemy
Мой обычный выбор:
| Проект | ORM | Причина |
|---|---|---|
| FastAPI (sync) | SQLAlchemy 2.0 | Мощь и гибкость |
| FastAPI (async) | Tortoise ORM | Native async |
| Django | Django ORM | Встроенная в фреймворк |
| Pequые скрипты | Peewee | Простота |
| Микросервисы | SQLAlchemy Core | Скорость и контроль |
Практические советы при выборе ORM:
- Размер проекта: маленький → Peewee, большой → SQLAlchemy
- Async требуется? → Tortoise, SQLAlchemy с asyncio
- Используешь Django? → Django ORM
- FastAPI + хотишь лучше? → SQLAlchemy 2.0 или SQLModel
- Производительность критична? → SQLAlchemy Core или raw SQL
Типичные ошибки при работе с ORM:
# ❌ N+1 проблема
users = User.objects.all() # 1 query
for user in users:
print(user.posts.count()) # N additional queries
# ✅ Использовать select_related/prefetch_related (Django)
users = User.objects.prefetch_related('posts').all()
# ✅ Использовать joinedload (SQLAlchemy)
from sqlalchemy.orm import joinedload
users = session.query(User).options(joinedload(User.posts)).all()