SQLAlchemy tutorial

박상훈·2024년 12월 16일

FastAPI 

목록 보기
1/1
post-thumbnail

참고자료 : https://www.pythoncentral.io/introductory-tutorial-python-sqlalchemy/#google_vignette

sqlalchemy란 python에서 제공하는 ORM(Objective Relational Map) 패키지 이며 FastAPI에서 DB를 다룰때 많이 사용한다.

본 tutorial에서는 아래와 같은 것들을 한다.

  • sqlalchemy이용해서 sqlite table구성
  • 만든 table에 data insert
  • insert한 데이터 sqlalchemy에서 제공하는 query interface를 이용해서 가져와 보기

디렉토리 구조

루트 디렉토리 이름은 자기 마음대로 해도 됨.

sqlalchemy_declarative.py

DB에서 사용할 Table을 sqlalchemy를 이용해서 python class형태로 정의한다.

전체 코드는 아래와 같다.

##sqlalchemy tutorial code(1)
##Create Table

import os
import sys
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine

##declarative_base()는 데이터베이스 모델을 정의할 수 있는 기반 클래스를 만드는 역할을 한다. 
##declarative_base()는 함수이지만 클래스 객체를 반환한다. 
##즉 declarative_base()는 새로운 클래스 객체를 생성하는 함수이다. 
Base = declarative_base()

class Person(Base):
    __tablename__= 'person'
    ## Here we define columns for the table person
    ## Notice that each column is also a normal Python instance attribute 
    id = Column(Integer, primary_key=True) ##id를 primary key로 설정
    name = Column(String(250), nullable=False) ##String(250)이 django orm에서 max_length=250이랑 같은 거인 듯? 

class Address(Base):
    __tablename__='address'
    ##Here we define columns for the table address.
    ##Notice that each column is also a normal Python instance attribute.
    id = Column(Integer, primary_key=True)
    street_name = Column(String(250))
    street_number = Column(String(250))
    post_code = Column(String(250), nullable=False) ##nullable=False가 django ORM에서 null=True인듯
    person_id = Column(Integer, ForeignKey('person.id'))
    person = relationship(Person)
    

## Create an engine that stores data in the local directory's sqlalchemy_example.db file
engine = create_engine('sqlite:///sqlalchemy_example.db')

## Create all tables in the engine. This is equivalent to "Create Table"
## statements in raw SQL.
Base.metadata.create_all(engine)

Base = declarative_base() : declarative_base()는 Table을 정의하는데 필요한 metaclass를 return한다. sqlalchemy를 이용해서 table을 정의할때 각 table class들은 모두 해당 metaclass를 상속해야 한다.
또한 이 클래스는 상속 클래스들을 알아서 인지하고 추적하여 매핑해준다.


engine = create_engine('databaseURL') : databaseURL과 연결한다. 이때 databaseURL에 해당하는 DB가 존재하지 않으면 현재 디렉토리에 databaseURL에 해당하는 DB 파일을 생성한다.

sqlite는 DB가 파일형식으로 존재한다.
sqlite같은 경우에는 dburl이 존재하지 않는 db면 해당 dir에 그에 해당하는 db file을 생성을 하는데 이게 sqlite만 그렇게 되는건지 아니면 postgresql같은 다른 DB들도 해당하는 DB가 없으면 자동으로 생성해 주는 건지는 잘 모르겠다.

Base.metadata.create_all(engine) : engine에 해당 하는 DB에다가 Base클래스를 상속받아 정의된 Table class들을 매핑해서 Table들을 생성해 준다.
쉽게 말하면 걍 create table

create_all()메서드는 처음 Table을 정의하여 생성할때 사용
이전에 만들어져 있는 table을 연결하여 조작할 때에는
bind() 메서드 사용.



해당 코드를 실행하면 같은 dir에 sqlalchemy_example.db라는 파일이 생긴 것을 볼 수 있을 것이다.



sqlalchemy_insert.py

DB와 Table을 만들었으니 이제 sqlalchemy에서 제공하는 orm interface를 사용하여 DB에 값을 넣어보자.

전체 코드는 아래와 같다.

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from sqlalchemy_declarative import Address, Base, Person

engine = create_engine('sqlite:///sqlalchemy_example.db')

# Bind the engine to the metadata of the Base class so that the
# decalratives can be accessed through a DBSession instance
Base.metadata.bind = engine


# sessionmaker()는 세션 객체를 생성하는 팩토리 함수를 반환한다. 
DBSession = sessionmaker(bind=engine)
# A DBSession() instance establishes all conversations with the database
# and represents a "staging zone" for all the objects loaded into the
# database session object. Any change made against the objects in the 
# session won't be persisted into the database until you call
# session.commit(). If you're not happy about the changes, you can
# rever all of them back to the last commit by calling 
# session.rollback()

# sessionmaker()로 부터 생성된 팩토리 함수를 이용해서 실제 session object를 생성
session = DBSession()


# Insert a person in the person table
new_person = Person(name='new person')
session.add(new_person)
session.commit()


# Insert an Address in the address table
new_address = Address(post_code='00000', person=new_person)
session.add(new_address)
session.commit()
  1. create_engine('dburl')을 이용해서 조작하고자 하는 DB를 연결해주고

  2. Base.metadata.bind=engine을 통해서 DB에 있는 table과 연결해준다.

  3. sessionmaker()를 이용해서 DBsessioin을 열어준다.

  4. 이전에 정의해둔 Table class를 이용해서 DB에 저장하고자 하는 data를 만들어 주고

  5. session.add(), session.commit()을 이용해서 DB에 값을 넣어 준다.

sqlalchemy ORM interface

python shell에서 아래와 같은 명령어를 쳐보면서 어떻게 작동하는지 알아보라.

>>> from sqlalchemy_declarative import Person, Base, Address
>>> from sqlalchemy import create_engine
>>> engine = create_engine('sqlite:///sqlalchemy_example.db')
>>> Base.metadata.bind = engine
>>> from sqlalchemy.orm import sessionmaker
>>> DBSession = sessionmaker()
>>> DBSession.bind = engine
>>> session = DBSession()
>>> # Make a query to find all Persons in the database
>>> session.query(Person).all()
[<sqlalchemy_declarative.Person object at 0x2ee3a10>]
>>>
>>> # Return the first Person from all Persons in the database
>>> person = session.query(Person).first()
>>> person.name
u'new person'
>>>
>>> # Find all Address whose person field is pointing to the person object
>>> session.query(Address).filter(Address.person == person).all()
[<sqlalchemy_declarative.Address object at 0x2ee3cd0>]
>>>
>>> # Retrieve one Address whose person field is point to the person object
>>> session.query(Address).filter(Address.person == person).one()
<sqlalchemy_declarative.Address object at 0x2ee3cd0>
>>> address = session.query(Address).filter(Address.person == person).one()
>>> address.post_code
u'00000'

각 session을 열면서 얻은 session객체를 이용한다.

session.query(TableClass)가 django에서 TableClass.objects와 동일한 역할을 한다.
참고로 django에서는 DBsession관리를 자동으로 알아서 해줬다.

sqlalchemy에서 제공하는 query method들

ref - https://code-escape.tistory.com/101

query().filter(조건) : 조건에 맞는 데이터 조회
이때 조건에 맞는 데이터를 찾아서 query object형태로 반환한다.
해당 데이터를 얻을려면 여기다가 다시 데이터를 얻는 query메서드를 사용해야 각 데이터 세부사항(각 clolumn)에 접근할 수 있다.

query().get(primarKey) : primaryKey에 해당하는 데이터를 즉시 가져옴. filter랑 다르게 query object가 아닌 조건에 맞는 DB Table의 하나의 열 그자체를 반환함.

django의 objects.filter()objects.get()도 위와 비슷한 차이점이 있었다.

query().first() : 첫 번째꺼 조회

query().count() : record갯수 가져오기

query().all() : 모든 record 가져오기

기타 등등 추가적인건 첨부해놓은 reference 참고하기

0개의 댓글