๋ ์ง: 2025-06-08
Python ์ํ๊ณ์์ ORM(Object-Relational Mapping) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ํ๋๋ ๋ ๊ฐ์ง๋ ๋ฐ๋ก Django ORM๊ณผ SQLAlchemy์ ๋๋ค.
๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ชจ๋ RDB์ ๊ฐ์ฒด์งํฅ ๋ชจ๋ธ ๊ฐ์ ๋งคํ์ ์ ๊ณตํ์ง๋ง, ์ฟผ๋ฆฌ ์์ฑ ๋ฐฉ์๊ณผ ์ถ์ํ ์์ค์ ์์ด ๊ทน๋ช ํ ์ฐจ์ด๋ฅผ ๋ณด์ ๋๋ค.
ํ์๋ Django ๊ฒฝ๋ ฅ๋ง ๊ฑฐ์ 7๋ ๋๊ฒ ๊ฐ์ง๊ณ ์๋ ์ํฉ์์ SQLAlchemy ๊ธฐ๋ฐ์ FastAPI ๊ฐ๋ฐ์ ํด์ผํ๋ ์ํฉ์ด ๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ณธ์ง์ ์ฐจ์ด์์ ๋ฐ์ํ๋ ์ด์ง๊ฐ์ผ๋ก ์ด๊ธฐ์ ๊ณ ์์ผ๋ก ์ข ํ๊ณ ์๋๊ฒ ๊ฐ์ต๋๋ค. ใ ใ ใ
๊ทธ๋์ ์ด ๊ธ์์๋ SQLAlchemy ์ค๋ฌด๋ฅผ ์ํ Django ๋๋น ์ฃผ์ Tip ์๊ฐ์ ๋ณต์กํ ์กฐ๊ฑด ํํฐ + ๊ด๊ณ ๋ก๋ฉ + ์ ๋ ฌ์ด ์์ธ ์ค์ ์์ ๋ฅผ ๊ธฐ์ค์ผ๋ก, Django ORM๊ณผ SQLAlchemy๊ฐ ์ด๋ป๊ฒ ์ ๊ทผ ๋ฐฉ์์ด ๋ค๋ฅธ์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
tags__name="X"
์๋์ผ๋ก ์ค๊ฐ ํ
์ด๋ธ ์ฒ๋ฆฌpost_tag_table
๊ฐ์ association table์ ์ง์ join ํด์ผ ํจโ ์ค์ ์์:
stmt = (
select(Post)
.join(post_tag_table, Post.id == post_tag_table.c.post_id)
.join(Tag, Tag.id == post_tag_table.c.tag_id)
.where(Tag.name == "ํ์ด์ฌ")
)
๐ ์ค๊ฐ ํ ์ด๋ธ ์์ด join(Tag) ํ๋ฉด ๋ฌด์กฐ๊ฑด ์๋ฌ ๋ฉ๋๋ค
.join()
์ด ์๋๋ผ .options()
select_related("author")
ํ ์ค.join()
์ SQL JOIN์ด๊ณ , .options(selectinload(...))
๋ก ๊ด๊ณ ๋ฐ์ดํฐ ๋ก๋ฉโ ์ค์ ์์:
select(Post).options(selectinload(Post.author))
๐ join()
์ผ๋ก๋ relationship์ด ์๋ ๋ก๋ฉ๋์ง ์์. ๋จ์ ์กฐ์ธ๋ง.
posts.filter(tags__name="X")
OKwhere(Tag.name == "X")
์ ์ ๋ฐ๋์ join(Tag)
๋ช
์ํด์ผ ํจโ ์๋ชป๋ ์:
select(Post).where(Tag.name == "ํ์ด์ฌ") # โ join์ด ์์ผ๋ฉด ์คํ ์๋ฌ
โ ์ฌ๋ฐ๋ฅธ ์:
select(Post).join(Post.tags).where(Tag.name == "ํ์ด์ฌ")
.options()
๋ ๋ก๋ฉ ์ ๋ต์ผ ๋ฟ, ํํฐ๋ง์๋ ์๋ฌด ํจ๊ณผ ์์ํท๊ฐ๋ฆฌ๋ ํจํด
select(Post).options(selectinload(Post.tags)).where(Tag.name == "ํ์ด์ฌ") # โ ์๋ฌ
๐ options()
๋ ์ฟผ๋ฆฌ ์กฐ๊ฑด์ ์ํฅ์ ์ฃผ์ง ์์
โ ์ค์ ์กฐ์ธ์ join()
์ผ๋ก, ๋ฐ์ดํฐ ๋ก๋ฉ์ options()
๋ก ๋ฐ๋ก ์จ์ผ ํจ
select()
๊ธฐ๋ฐ ์ฒด์ด๋์ด ๋ง์์ง์๋ก ์ฝ๋๊ฐ ์์ง์ผ๋ก ๊ธธ์ด์ง๋คโ ์์:
select(Post)
.join(User)
.where(and_(..., ...))
.order_by(...)
.options(selectinload(...), selectinload(...))
๐ ํ ์ค์ฉ ์ ๋ฆฌํ๋ ์ฝ๋ ์ปจ๋ฒค์ ์ ํ ๋ด์์ ์ ํด๋๋ ๊ฒ ์ค๋ฌด์์ ์ค์
ํฌ์ธํธ | Django์์๋โฆ | SQLAlchemy์์๋โฆ |
---|---|---|
๊ด๊ณ ์กฐ์ธ | ์๋ ์ถ๋ก | ๋ช ์์ join ํ์ |
๊ด๊ณ ๋ก๋ฉ | select_related | options(selectinload) |
N:N ๊ด๊ณ | ์์์ ์ฒ๋ฆฌ | ์ค๊ฐ ํ ์ด๋ธ ์๋ ๋ช ์ |
์กฐ๊ฑด ํํฐ | ๊ด๊ณ ํ๋ ๊ฒฝ๋ก๋ก ๊ฐ๋ฅ | join + where ์กฐ๊ฑด ์กฐํฉ ํ์ |
๊ฐ๋ ์ฑ | ์ํ์ chain | ์์ง์ ์ฒด์ด๋ ๊ตฌ์กฐ |
relationship()
์ ๊ผญ ๋ฐฉํฅ/์ต์
๋ช
์ (back_populates
, lazy
, cascade
๋ฑ)association_table
๋ก ๋ฐ๋ก ์ ์ํด๋๊ณ import ํด์ ์จ์ผ ๊น๋ํจ๋ค์๊ณผ ๊ฐ์ ๋ชจ๋ธ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ํฉ๋๋ค.
User(1) โ Post(N)
Post(N) โ Tag(M)
(ManyToMany)์กฐ๊ฑด:
Post.title
์ โFastAPIโ ํฌํจPost.published_at IS NOT NULL
Tag.name == "ํ์ด์ฌ"
User.name
๊ธฐ์ค ์ ๋ ฌPost.user
,Post.tags
๋ ๋ฏธ๋ฆฌ ๋ก๋ฉ (Eager Load)
Post.objects.select_related("user") \
.prefetch_related("tags") \
.filter(
title__icontains="FastAPI",
published_at__isnull=False,
tags__name="ํ์ด์ฌ"
) \
.order_by("user__name")
__
๋ก ์ ๊ทผstmt = (
select(Post)
.join(Post.user)
.join(post_tag_table, post_tag_table.c.post_id == Post.id)
.join(Tag, Tag.id == post_tag_table.c.tag_id)
.where(
and_(
Post.title.ilike("%FastAPI%"),
Post.published_at.is_not(None),
Tag.name == "ํ์ด์ฌ"
)
)
.order_by(User.name.asc())
.options(
selectinload(Post.user),
selectinload(Post.tags)
)
)
results = session.exec(stmt).all()
.options(selectinload(...))
๋ณ๋ ์ค์ ํญ๋ชฉ | Django ORM | SQLAlchemy |
---|---|---|
์ถ์ํ ์์ค | ๋งค์ฐ ๋์ (๋ชจ๋ธ ๊ธฐ๋ฐ DSL) | ๋ฎ์ (SQL ๊ธฐ๋ฐ ์กฐํฉ) |
๊ด๊ณ ๋ก๋ฉ | select_related / prefetch_related | selectinload / joinedload (options) |
N:N ๊ด๊ณ ์ฒ๋ฆฌ | ORM์ด ์๋ ์กฐ์ธ | ์ค๊ฐ ํ ์ด๋ธ ์ง์ ๋ช ์ ํ์ |
์ฟผ๋ฆฌ ๊ฐ๋ ์ฑ | ๊ฐ๊ฒฐ, ์๋ ์ค์ฌ | ๋ช ์์ , ๊ตฌ์กฐ ์ค์ฌ |
์ฟผ๋ฆฌ ์ ์ฐ์ฑ | ์ ํ์ | ๋งค์ฐ ๋์ |
ํ์ต ๋์ด๋ | ์ง์ ์ฅ๋ฒฝ ๋ฎ์ | ์ง์ ์ฅ๋ฒฝ ๋์, ์ ๋ฐ ์ ์ด ๊ฐ๋ฅ |
Django ORM์ ์น ๊ฐ๋ฐ ์์ฐ์ฑ ๊ทน๋ํ๋ฅผ ๋ชฉํ๋ก, ์ฟผ๋ฆฌ ์์ฑ๋ ๋ชจ๋ธ ์ค์ฌ ์ถ์ํ์ ์ง์ค โ ์ ์ธ์ ์ด๊ณ ์ง๊ด์ ์ธ API ์ ๊ณต
SQLAlchemy๋ SQL ์์ฒด๋ฅผ ์ต๋ํ ์์ ๋กญ๊ฒ ํํํ๋ ค๋ ์ฒ ํ์ ๊ธฐ๋ฐ์ผ๋ก ์ค๊ณ โ ์ฟผ๋ฆฌ ๊ตฌ์กฐ์ ๋ํ ์์ ํ ์ ์ด๊ถ์ ๊ฐ๋ฐ์์๊ฒ ์์
์ํฉ | ์ถ์ฒ ORM |
---|---|
๋น ๋ฅธ CRUD ์น ์๋น์ค ๊ตฌ์ถ | โ Django ORM |
๋ณต์กํ ์กฐ์ธ, ์ฑ๋ฅ ์ต์ ํ, SQL ์ ์ด | โ SQLAlchemy |
๋ช ํํ ๊ด๊ณ ์ ์ + ์๋ํ๋ ๋ก๋ฉ | โ Django ORM |
ORM์ ๋๋๋๋ SQL ์กฐํฉ, ์๋ธ์ฟผ๋ฆฌ, Union ๋ฑ | โ SQLAlchemy |
๋ ORM์ ์๋ก ๋ค๋ฅธ ์ฒ ํ์ ๊ฐ๊ณ ์๊ณ , ์ฌ์ฉํ๋ ๊ฐ๋ฐ์์๊ฒ๋ ๋ค๋ฅธ ๊ธฐ๋์ ์ฑ ์์ ์๊ตฌํฉ๋๋ค. ๋จ์ํ โ์ด๋ค ๊ฒ ๋ ๋ซ๋คโ๊ฐ ์๋๋ผ, **โ์ด๋ค ์ํฉ์ ์ด๋ค ๋๊ตฌ๊ฐ ์ ํฉํ๊ฐโ**๋ฅผ ์ดํดํ๊ณ ์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
ํ์๋ Django ORM์ ๊ฐ๊ฒฐํจ์ ์ต์ํด ์์์ง๋ง, SQLAlchemy๋ฅผ ์ ํ๋ฉด์ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ณด๋ค ๋ช ํํ๊ฒ ํต์ ํ ์ ์๋ ๋งค๋ ฅ์ ๋๊ผ์ต๋๋ค.
ORM์ ๋์ด์ SQL๊น์ง ์ดํดํ๊ณ ์ถ์ ๊ฐ๋ฐ์๋ผ๋ฉด SQLAlchemy๋ ํ ๋ฒ ๋์ ํด๋ณด์๊ธธ ์ถ์ฒํฉ๋๋ค.