SQLAlchemy 1.1 - index_property
SQLAlchemy 1.1에는 index_property라는, Indexable 컬럼 (JSON, ARRAY, HSTORE 등)의 속성 하나를 마치 컬럼과 비슷한 프로퍼티처럼 다룰 수 있는 기능이 추가되었습니다.
제가 추가한 기능이라 소개 시간.
1.1에 추가된 것 소개 문서와 Indexable에 관한 문서로 나누어서 다루어지고 있는데, 이 글에서는 무엇이 좋은지 1.0의 코드와 비교해 보려고 합니다.
먼저 id 밖의 모든 자료는 data라는 JSON 컬럼에 저장하는 모델 Person을 생각해 봅시다.
class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) data = Column(JSON) # 여기에 모든 속성이 들어간다
만일 data에 name이라는 속성이 들어있다면, 1.0에서는 다음과 같이 접근합니다.
person = Person(data={'name': 'youknowone'}) # 만들 때 print(person.data['name']) # 가져올 때
1.1에 새로 추가된 index_property는 여기서 name을 마치 하나의 컬럼과 비슷하게 다룰 수 있도록 도와줍니다.
class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) data = Column(JSON) # 여기에 모든 속성이 들어간다 name = index_property('data', 'name')
처음 정의에서 name이라는 index_property를 추가했습니다. data라는 컬럼의 name이라는 키와 연결시킨 프로퍼티라는 뜻이에요.
이 프로퍼티는 만능이어서, 여러분이 SQLAlchemy에서 기존의 프로퍼티에 기대하던 모든 일을 할 수 있어요.
person = Person(name='youknowone') # 생성 assert person.name == 'youknowone' # 조회 person.name = 'sqlalchemy' # 변경 session.query(Person).filter(Person.name.astext == 'sqlalchemy') # 쿼리
이것들을 다시 index_property 없이, 1.0과 호환되도록 써 본다면,
class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) data = Column(MutableDict.as_mutable(JSON)) # 아까와 달리 내용 변경을 추적하려면 MutableDict로 타입을 감싸주어야 한다. person = Person(data={'name': 'youknowone'}) # 생성 assert person.data['name'] == 'youknowone' # 조회 person.data['name'] = 'sqlalchemy' # 변경. 위에서 MutableDict를 써야만 가능 session.query(Person).filter(Person.data['name'].astext == 'sqlalchemy') # 쿼리
각각의 코드가 훨씬 길어지는 것은 물론이고 MutableDict 역시 도입해서 함께 써야 합니다. 물론 1.0에서도 이걸 일일이 풀어쓰기 보다는 비슷한 인터페이스로 감싸서 쓰기들 원하는 사람들이 있었죠. 이번에는 이 프로퍼티를 직접 만들어 봅시다.
class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key=True) data = Column(JSON) # 여기에 모든 속성이 들어간다 @hybrid_property def name(self): return self.data.get('name', None) @name.setter def name(self, new_value): data = self.data.copy() # 꼭 복사할 필요는 없지만 name에 바로 대입하면 변경을 추적하지 못해요 data['name'] = new_value self.data = data @name.expression def name(self): return self.data['name']
한 줄의 index_property로 가능하던 일을 세 개의 메서드를 구현해 가며 만들어야만 합니다. 의욕이 꺾이는 일이지요. 그러니 앞으로는 index_property를 꼭 쓰세요.
세줄 요약:
SQLAlchemy 1.1에는 index_property라는게 생겼다.
index_property를 쓰면 JSON, ARRAY 등의 한 index를 가리키는 프로퍼티를 만들 수 있다.
만들고 나면 마치 그 이름의 컬럼인 것과 비슷하게 쓸 수 있다.












