728x90
반응형
MetaData
- MetaData란 데이터베이스 구조와 schema를 기술하는 데이터에 대한 데이터
- Database table, column, data type, index, restriction, trigger, view 등을 설명하는 정보 포함
- 데이터베이스의 스키마를 정의하고 관리하는 역할
- SQLAlchemy Core(SQL을 직접 작성, Connection 사용)과 ORM(객체 지향 접근 방식, Session 사용)에서 모두 MetaData를 사용하여 SQL 쿼리를 작성하고 실행 가능
- Core의 경우 MetaData 객체를 생성하는 방식으로 사용되며, 주로 Connection 객체와 함께 사용
- Connection 객체는 낮은 수준의 SQL 작업을 수행하는 데 적합
- Session 객체를 사용할 수 있긴 함. 이 경우, Connection 객체를 내부적으로 사용하여 데이터베이스와 상호작용 하지만 트랜잭션 관리, 연결 풀 관리, 작업의 일관성 유지 등 여러 장점을 제공받을 수 있음
- ORM의 경우 베이스클래스를 상속받는 방식으로 사용되며, 주로 Session 객체와 사용
- Session 객체는 트랜잭션 관리, 연결 풀 관리, 작업의 일관성 유지 등을 제공
- Core의 경우 MetaData 객체를 생성하는 방식으로 사용되며, 주로 Connection 객체와 함께 사용
- 주요 구성 요소: Table, Column, Primary Key, Foreign Key, Index, Unique Constraint, Check Constraint, View, Trigger
1. MetaData 객체 생성 및 기본 테이블 정의
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, ForeignKey, Date
# 엔진 생성
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True)
# MetaData 객체 생성
metadata = MetaData()
# 고객 테이블 정의
customer_table = Table(
'customer', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50), nullable=False),
Column('email', String(100), nullable=False, unique=True)
)
# 주문 테이블 정의
order_table = Table(
'order', metadata,
Column('id', Integer, primary_key=True),
Column('order_date', Date, nullable=False),
Column('customer_id', Integer, ForeignKey('customer.id'), nullable=False)
)
# 데이터베이스에 테이블 생성
metadata.create_all(engine)
2. 데이터 삽입 및 조회
with engine.connect() as connection:
connection.execute(customer_table.insert().values(id=1, name='John Doe', email='john@example.com'))
connection.execute(customer_table.insert().values(id=2, name='Jane Smith', email='jane@example.com'))
connection.execute(order_table.insert().values(id=1, order_date=date.today(), customer_id=1))
connection.execute(order_table.insert().values(id=2, order_date=date.today(), customer_id=2))
# 데이터 조회
with engine.connect() as connection:
result = connection.execute(select([customer_table]))
for row in result:
print(row)
- Core에서 Session 사용
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, select
from sqlalchemy.orm import sessionmaker
# 데이터베이스 엔진 생성
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True)
# MetaData 객체 생성
metadata = MetaData()
# 테이블 정의
user_table = Table(
'user_account', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(30)),
Column('fullname', String)
)
# 데이터베이스에 테이블 생성
metadata.create_all(engine)
# 세션 생성기 생성
SessionLocal = sessionmaker(bind=engine)
# 데이터 삽입 및 조회
with SessionLocal() as session:
# 데이터 삽입
session.execute(user_table.insert().values(id=1, name='John', fullname='John Doe'))
session.execute(user_table.insert().values(id=2, name='Jane', fullname='Jane Doe'))
session.commit()
# 데이터 조회
result = session.execute(select([user_table]))
for row in result:
print(row)
Base Class
- Core를 사용할 때는 MetaData 객체를 생성하여 메타데이터를 관리하지만 ORM을 사용할 때는 베이스 클래스를 생성해서 관리
- Core는 주로 더 낮은 수준의 SQL 작업을 수행하는데 적합
- ORM은 더 높은 수준의 객체 지향적 데이터베이스 작업을 수행하는데 적합
- 상황에 따라 두 방법 중 하나를 선택하거나 혼용하여 사용
- declarative_base() 함수를 통해 베이스 클래스 생성하거나 DecalrativeBase 클래스를 사용하여 메타데이터 관리
- 내부적으로 MetaData 객체를 포함하고 있음
- 베이스 클래스를 상속받아 데이터베이스 테이블과 매핑되는 ORM 클래스를 정의
- SQLAlchemy 2.0부터 DecalarativeBase를 사용하여 베이스 클래스를 정의하는 것이 권장
# declarative_base()를 사용하는 방식
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 데이터베이스 엔진 생성
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True)
# 베이스 클래스 생성
Base = declarative_base()
# ORM 매핑 클래스 정의
class User(Base):
__tablename__ = 'user_account'
id = Column(Integer, primary_key=True)
name = Column(String(30))
fullname = Column(String)
# 데이터베이스 테이블 생성
Base.metadata.create_all(engine)
# 세션 생성기 생성
SessionLocal = sessionmaker(bind=engine)
# 데이터 삽입 및 조회
with SessionLocal() as session:
new_user = User(name='John', fullname='John Doe')
session.add(new_user)
session.commit()
users = session.query(User).all()
for user in users:
print(f"{user.name}, {user.fullname}")
# DeclarativeBase 클래스를 사용하는 방식
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import DeclarativeBase, sessionmaker, mapped_column
# 데이터베이스 엔진 생성
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True)
# 베이스 클래스 생성
class Base(DeclarativeBase):
pass
# ORM 매핑 클래스 정의
class User(Base):
__tablename__ = 'user_account'
id: int = mapped_column(Integer, primary_key=True)
name: str = mapped_column(String(30))
fullname: str = mapped_column(String)
def __repr__(self):
return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"
# 메타데이터를 사용하여 테이블 생성
Base.metadata.create_all(engine)
# 세션 생성기 생성
SessionLocal = sessionmaker(bind=engine)
# 데이터 삽입 및 조회
with SessionLocal() as session:
new_user = User(name='John', fullname='John Doe')
session.add(new_user)
session.commit()
users = session.query(User).all()
for user in users:
print(f"{user.name}, {user.fullname}")
왜 Core와 ORM을 구분해서 사용할까?
- 성능: Core는 SQL 쿼리를 직접 제어할 수 있으므로 성능 최적화가 필요한 경우 유리
- 복잡한 쿼리: Core는 복잡한 SQL 쿼리를 작성하고 실행할 수 있는 유연성을 제공
- 추상화 수준: ORM은 높은 수준의 추상화를 제공하여 개발 생산성을 높이지만, 모든 상황에 적합하지 않을 수 있음
- 특정 요구사항: 일부 프로젝트에서는 ORM의 높은 추상화 수준이 필요하지 않을 수 있으며, Core의 세밀한 제어가 필요한 경우 존재
Table Reflection
- SQLAlchemy에서 기존 데이터베이스의 테이블 구조를 읽어와서 Python 객체로 생성하는 과정
- SQLAlchemy를 사용하여 Python에서 해당 테이블을 매핑하고 사용하려면 테이블 정의를 포함한 메타데이터를 여전히 정의 해야 함
- 데이터베이스와 상호작용하기 위해 테이블의 구조를 알고 있어야 하기 때문
- 직접 테이블을 생성하는 대신, 데이터베이스에 존재하는 테이블의 메타데이터를 reflection을 통해 자동으로 불러올 수 있음
- Core 스타일에서의 리플렉션
from sqlalchemy import create_engine, MetaData, Table
# 데이터베이스 엔진 생성
engine = create_engine("sqlite:///existing_database.db", echo=True)
# MetaData 객체 생성
metadata = MetaData()
# 리플렉션을 사용하여 테이블 로드
# user_account 테이블의 구조를 자동으로 로드하여 메타데이터 객체로 생성
user_table = Table('user_account', metadata, autoload_with=engine)
# 데이터 조회
with engine.connect() as connection:
result = connection.execute(user_table.select())
for row in result:
print(row)
- ORM 스타일에서의 리플렉션
from sqlalchemy import create_engine, Table
from sqlalchemy.orm import DeclarativeBase, sessionmaker
# 데이터베이스 엔진 생성
engine = create_engine("sqlite:///existing_database.db", echo=True)
# Declarative Base 생성
class Base(DeclarativeBase):
pass
# ORM 매핑 클래스 정의
# 직접 컬럼을 정의하는 대신 __table__ 속성을 사용하여 테이블을 로드
class User(Base):
__tablename__ = 'user_account'
__table__ = Table(__tablename__, Base.metadata, autoload_with=engine)
def __repr__(self):
return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"
# 세션 생성기 생성
SessionLocal = sessionmaker(bind=engine)
# 데이터 조회
with SessionLocal() as session:
users = session.query(User).all()
for user in users:
print(user)
728x90
반응형
'Programming Language > Python' 카테고리의 다른 글
[SQLAlchemy] 5. ORM을 사용한 SELECT (0) | 2024.06.22 |
---|---|
[SQLAlchemy] 4. ORM을 사용한 INSERT (0) | 2024.06.22 |
[SQLAlchemy] 2. Connection, Commit, Query, Bound parameters (0) | 2024.06.22 |
[SQLAlchemy] 1. Engine (0) | 2024.06.22 |
[FastAPI] 12. Update: PUT, PATCH (0) | 2024.06.20 |