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

Что такое сессия в Django ORM?

2.0 Middle🔥 151 комментариев
#Django

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

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

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

# Сессия в Django ORM

Краткий ответ

Сессия в Django ORM — это объект, который управляет жизненным циклом объектов модели и их взаимодействием с базой данных. В Django сессия работает автоматически и неявно.

Важное уточнение: Django vs SQLAlchemy

Django ORM (встроенная ORM)

В Django сессия работает неявно и автоматически:

from django.db import models

class User(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField(unique=True)

# Создание
user = User.objects.create(name="John", email="john@example.com")

# Чтение
user = User.objects.get(id=1)

# Обновление и сохранение
user.name = "Jane"
user.save()

# Удаление
user.delete()

SQLAlchemy (отдельная ORM)

В SQLAlchemy сессия работает явно:

from sqlalchemy.orm import Session

with Session(engine) as session:
    user = User(name="John", email="john@example.com")
    session.add(user)
    session.commit()
    
    user = session.query(User).filter_by(id=1).first()
    user.name = "Jane"
    session.commit()

Что такое сессия в контексте ORM?

Сессия — это:

  1. Контекст работы с объектами БД
  2. Кэш объектов, загруженных из БД
  3. Транзакция — группа операций, которые либо все выполнятся, либо все откатятся
  4. Отслеживание изменений — сессия видит, какие объекты изменились

В Django: Явное управление транзакциями

from django.db import transaction

# Способ 1: Декоратор
@transaction.atomic
def create_user_with_profile():
    user = User.objects.create(name="John")
    profile = Profile.objects.create(user=user, bio="Hi")

# Способ 2: Context manager
with transaction.atomic():
    user = User.objects.create(name="John")
    profile = Profile.objects.create(user=user, bio="Hi")

# Способ 3: Savepoint
with transaction.atomic():
    try:
        user = User.objects.create(name="John")
        with transaction.atomic():
            profile = Profile.objects.create(user=user)
    except Exception:
        pass

В SQLAlchemy: Явная сессия

from sqlalchemy.orm import Session

# Способ 1: Контекстный менеджер
with Session(engine) as session:
    user = User(name="John")
    session.add(user)
    session.commit()

# Способ 2: Явное управление
session = Session(engine)
try:
    user = User(name="John")
    session.add(user)
    session.commit()
except Exception:
    session.rollback()
    raise
finally:
    session.close()

# Способ 3: Вложенные транзакции
with Session(engine) as session:
    user = User(name="John")
    session.add(user)
    session.flush()
    
    try:
        with session.begin_nested():
            profile = Profile(user_id=user.id)
            session.add(profile)
    except Exception:
        pass
    
    session.commit()

Состояния объекта в сессии

SQLAlchemy (явное)

session = Session(engine)

# 1. Transient — объект создан, но не в сессии
user = User(name="John")
print(user in session)

# 2. Pending — добавлен в сессию, но не в БД
session.add(user)
print(user in session)

# 3. Persistent — в сессии и в БД
session.commit()
print(user.id)

# 4. Detached — был в сессии, но сессия закрыта
session.close()
print(user in session)

Django (неявное)

В Django состояния менее явные:

# Transient
user = User(name="John")
print(user.id)

# Persistent
user.save()
print(user.id)

# После save() всё работает
user.name = "Jane"
user.save()

Проблемы с сессиями

1. Lazy Loading (N+1 проблема)

# Django
users = User.objects.all()
for user in users:
    print(user.profile.bio)

# Решение: select_related
users = User.objects.select_related("profile").all()

# SQLAlchemy
with Session(engine) as session:
    users = session.query(User).all()
    for user in users:
        print(user.profile.bio)

# Решение: joinedload
users = session.query(User).options(joinedload(User.profile))

2. Detached объект (SQLAlchemy проблема)

with Session(engine) as session:
    user = session.query(User).get(1)

print(user.profile.bio)  # DetachedInstanceError!

3. Identity Map (кэш)

# SQLAlchemy
with Session(engine) as session:
    user1 = session.query(User).get(1)
    user2 = session.query(User).get(1)
    print(user1 is user2)  # True!

# Django
user1 = User.objects.get(id=1)
user2 = User.objects.get(id=1)
print(user1 is user2)  # False

FastAPI + SQLAlchemy (практический пример)

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

engine = create_engine("postgresql://...")
SessionLocal = sessionmaker(bind=engine)

app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.post("/users/")
async def create_user(
    user_data: dict,
    db: Session = Depends(get_db)
):
    user = User(**user_data)
    db.add(user)
    db.commit()
    db.refresh(user)
    return user

@app.get("/users/{user_id}")
async def get_user(
    user_id: int,
    db: Session = Depends(get_db)
):
    user = db.query(User).get(user_id)
    if not user:
        raise HTTPException(status_code=404)
    return user

Лучшие практики

Django

# Хорошо: select_related для избежания N+1
users = User.objects.select_related("profile").all()

# Хорошо: transaction.atomic
@transaction.atomic
def create_user_with_profile():
    user = User.objects.create(name="John")
    Profile.objects.create(user=user)

SQLAlchemy

# Хорошо: контекстный менеджер
with Session(engine) as session:
    user = User(name="John")
    session.add(user)
    session.commit()

# Хорошо: joinedload для N+1
users = session.query(User).options(joinedload(User.profile)).all()

Вывод

Сессия — это контекст работы с БД. В Django она неявная и автоматическая, в SQLAlchemy — явная. Главное — понимать жизненный цикл объектов и оптимизировать N+1 проблемы.

Что такое сессия в Django ORM? | PrepBro