SQLAlchemy vs Django ORM: що вибрати для роботи з базою даних у Python веб-застосунках

💡 Усі статті, обговорення, новини про Python — в одному місці. Приєднуйтесь до Python спільноти!

Насправді вибір «правильного» ORM для конкретного застосунка є надзвичайно важливим кроком, не менш важливим, ніж вибір відповідної бази даних для вашого веб-застосунка.

Чому потрібен ORM?

Перш за все це автоматична генерація запитів (не пишете «сирі» SQL-запити, а працюєте з Python-об’єктами).

Також захист від SQL-ін’єкцій (сирі SQL-запити — вразливі).

Єдиний синтаксис для різних СУБД зменшує необхідність оновлення запитів при зміні СУБД).

Наступне завдання ORM автоматичне створення міграцій і управління ними.

Зменшення кількості повторюваного коду (створіть модель та використовуйте її).

Підтримка статичної типізації в Python.

Звичайно, ORM мають свої недоліки. У більшості випадків це стосується продуктивності запитів і додаткового споживання пам’яті веб-сервером. Проте зазвичай розробники віддають перевагу підтримуваності коду та його гнучкості, ніж передчасній оптимізації.

Головні відмінності SQLAlchemy та Django ORM

1. Опис моделей

Опис моделей є простим і лаконічним в обох ORM.

Django ORM

from django.db import models  
class Person(models.Model):  
    name = models.CharField(max_length=100)  
    age = models.IntegerField()

SQLAlchemy

from sqlalchemy import Column, Integer, String  
from sqlalchemy.orm import declarative_base  
Base = declarative_base()  
class Person(Base): 
    __tablename__ = 'persons’'  
    id = Column(Integer, primary_key=True)  
    name = Column(String(100))  
    age = Column(Integer)  

2. Обробка запитів

Прості запити

Обидві ORM добре справляються з простими запитами.

Django ORM

from django.db.models import Avg  
avg_age = Person.objects.aggregate(Avg('age'))

SQLAlchemy

from sqlalchemy.sql import func  
avg_age = session.query(func.avg(Person.age)).scalar() 

3. Складні запити

Обидві ORM добре справляються зі складними запитами. На проілюстрованому прикладі ми бачимо як вкладені запити з агрегаціями достатньо просто описуються і потім генеруються в 1 SQL запит.

SQLAlchemy (з підзапитом)

# Підзапит: обчислення середнього віку персон, згрупованих за першою літерою імені
avg_age_subquery = (
    select(
        func.left(Person.name, 1).label("first_letter"),
        func.avg(Person.age).label("avg_age")
    )
    .group_by(func.left(Person.name, 1))
    .subquery()
)
avg_alias = aliased(avg_age_subquery)
# Основний запит: вибір персон, які старші за середній вік у своїй групі
complex_query = (
    session.query(Person)
    .join(avg_alias, func.left(Person.name, 1) == avg_alias.c.first_letter)
    .filter(Person.age > avg_alias.c.avg_age)
)

Django ORM (з підзапитом)

avg_age_subquery = (
       Person.objects
       .annotate(first_letter=Substr('name', 1, 1))  # Перша буква імені
       .values('first_letter')
       .annotate(avg_age=Avg('age'))  # Середній вік для кожної букви
       .values('first_letter', 'avg_age')  # Залишаємо тільки необхідні поля
   )
   # Основний запит: вибір користувачів, які старші за середній вік у своїй групі
   complex_query = (
       Person.objects
       .annotate(first_letter=Substr('name', 1, 1)) 
       .filter(
    age__gt=Subquery(avg_age_subquery.filter(first_letter=OuterRef('first_letter')).values('avg_age')[:1])
       )
   )

4. Міграції

Django ORM має вбудовану систему міграцій, підтримує автоматичне генерування змін схеми бази даних.

SQLAlchemy не має вбудованої системи міграцій, потрібно використовувати Alembic для управління ними.

5. Обробка великих наборів даних

Обидві ORM підтримують вигрузку батчами.

Django ORM

for person in Person.objects.iterator(): 
    print(person.name) 

SQLAlchemy

for person in session.query(Person).yield_per(1000):
    print(person.name)

Порівняльна таблиця

Функціональність

Django ORM

SQLAlchemy

Простота використання

Так

Вимагає додаткових конфігурацій

Оптимізація складних запитів

Повний контроль

Повний контроль

Міграції

Вбудовані

Потрібен Alembic

Обробка великої кількості даних батчами

Повна підтримка

Повна підтримка

Висновки

Django ORM підходить, якщо:

  • Ви працюєте з Django-проектом.
  • Швидка розробка без зайвих налаштувань.

SQLAlchemy є кращим вибором, якщо:

  • Ви розробляєте мікросервіс і не хочете використовувати всю екосистему Django.
  • Завдяки додатковим конфігураціям хочете мати більше контролю для роботи з БД.

Загалом, як бачите порівняння, то немає великої різниці між цими двома ORM. Обидва інструменти дуже потужні і будуть у нагоді в будь-якому проекті. Django буде легше для початківців, бо має більш простіший інтерфейс для використання. Але не потрібно поспішати і робити висновок, що з її допомогою розробляються лише прості проекти. Я зустрічав достатньо складні проекти, які розроблені на Django і за продуктивністю вони не поступались проектам на SQLAlchemy.

SQLAlchemy у свою чергу вам дасть більше гнучкості у роботі з іншими бібліотеками, вам не потрібно буде використовувати екосистему Django (тільки якщо ви сильно захочете). Більша конфігурованість може стати в нагоді, якщо потріно буде робити додаткові оптимізації. Із мінусів, більший поріг входу, бо потрібно буде конфігурувати деякі речі в ORM самому. Додатково потрібно буде встановлювати Alembic для міграцій і розбиратись ще із ним.

Краще обирайте той інструмент, яким команда володіє краще і тоді розробка буде швидка і спокійна. 🙂

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному1
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
3. Складні запити

— в Django ORM повноцінна підтримка десь +/- на рівні ванільного SQL92 в той час як SQLAlchemy десь між 2003 та 2006

з усім що складніше SQL92 у джанго проблеми:
Підзапити — лише тривіальні речі типу наведеного прикладу чи використання EXISTS, щось складніше де потрібен WITH — лише через стороннє розширення для CTE у якого купа своїх проблем та тараканів.
Вікна (LAG, LEAD, OVER і т.д.) — типу навіть є, але по факту — дуже часто генерується взагалі некорректний SQL.

Розширення та специфіка різних діалектів (повнотекстовий пошук, масиви, XML/XPATH, JSON) — формально Django ORM щось таке вміє, але фактично — тільки повністю RAW SQL.
в SQLAlchemy — на 90% можна писати на ORM

SQLAlchemy 2x була релізнута в 23 році, а ви в 25році використовуєте 1.х версію в статті, печалька(((

На самом деле, вывод можно было бы сделать и без анализа.
Работаешь с Джангой — используешь ее ОРМ (ибо куда же ты денешься с подводной-то лодки?)
Работаешь вне Джанго фреймворка — ее ОРМ будет недоступна.

P.S. Алхимия хоть и мощная, но, как по мне, чрезмерно. Предпочитаю простенькую Peewee

Піві хіба не гівнокод у одному файлі?

Питання до автора, звідки такі висновки про джанго у 5 пункті? Документація говорить інше...

Дуже дякую за зауваження. Перевірив документацію, ви праві. Статтю підправив🙂

Підписатись на коментарі