Today I Learned
날짜
2024년 12월 24일 화요일
내용
secondary table에 필드를 추가하기
네이버 배너이미지에는 인스타그램 게시글의 사진이 포함될 수 있다. 한 게시글은 당연히 여러 이미지에 포함될 수도 있다. many to many를 설계 과정에서 어떻게 처리할지 고민하다가 secondary table로 구현했다.
id로 4를 가진 네이버 배너이미지데이터가 생성되고 이 배너이지에 포함되는 게시글 3개의 id가 1,3,5라면
naver_banner_image_id | instagram_post_id |
---|---|
4 | 1 |
4 | 3 |
4 | 5 |
secondary table에는 이렇게 저장이 된다. 만약 id가 12인 네이버 배너이미지가 생성되고 게시글을 3,5,22 를 id로 하는 데이터들을 포함한다면
naver_banner_image_id | instagram_post_id |
---|---|
4 | 1 |
4 | 3 |
4 | 5 |
12 | 3 |
12 | 5 |
12 | 22 |
이렇게 추가된다. 관계가 끊어지면 이 테이블에서도 해당 데이터는 삭제된다. 이 구조는 배너이미지가 어떤 게시글들을 포함하는 알려줄 수 있지만, 어떤 순서로 포함해야하는지는 알려주지 않는다. 실제로 생성할 때 고른 게시글 순서와 실제 순서가 다르다는 이슈도 발생했다.
이 부분을 처리하기 위해 secondary table에 index 필드를 추가했다. 각 게시글이 배너이미지 내에서 몇번째에 위치하는지를 저장하는 필드다. 아마 다음과 같이 생길거다.
naver_banner_image_id | instagram_post_id | index |
---|---|---|
4 | 1 | 1 |
4 | 3 | 2 |
4 | 5 | 3 |
12 | 3 | 3 |
12 | 5 | 2 |
12 | 22 | 1 |
이 필드가 추가되면서 데이터를 생성하는 코드 또한 변경해야 했다. 기존에 index 필드가 없을때는
1
2
3
instagram_post_list = [object, object, ..., object]
naver_banner_image.instagram_posts = instagram_post_list
db.commit()
이런식으로 작성하면 자동으로 secondary table에 데이터가 저장되었지만 이제는 index도 지정해줘야 한다. 그래서
1
2
3
4
5
6
7
8
9
10
11
post_dict = {post.origin_id: post for post in instagram_posts}
for index, origin_id in enumerate(origin_ids, start=1):
post = post_dict.get(origin_id)
if post:
association = models.naver_banner_image_instagram_post_association(
naver_banner_image_id=naver_banner_image.id,
instagram_post_id=post.id,
index=index,
)
db.add(association)
이런식으로 작성했으나
‘Table’ object is not callable
라는 오류가 발생했다. 평소 데이터베이스에 데이터를 추가할때 ORM(sqlalchemy)으로 정의한 객체를 생성하는 방식을 사용했다보니 똑같이 해서 발생한 오류였다. 기존에 사용하던 테이블과 이 secondary table은 다르게 정의되어 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# ORM으로 정의한 객체
class NaverBannerImage(Base):
"""
네이버 배너 이미지 정보를 담는 테이블
"""
__tablename__ = "naver_banner_image"
id = Column(Integer, primary_key=True, index=True, unique=True)
status = Column(TEXT)
# Table로 정의한 객체
# NaverBannerImage와 InstagramPost 간의 다대다 관계를 위한 중간 테이블 정의
naver_banner_image_instagram_post_association = Table(
"naver_banner_image_instagram_post_association",
Base.metadata,
Column(
"naver_banner_image_id",
Integer,
ForeignKey("naver_banner_image.id", ondelete="CASCADE"),
primary_key=True,
),
Column(
"instagram_post_id",
Integer,
ForeignKey("instagram_post.id", ondelete="CASCADE"),
primary_key=True,
),
Column(
"index",
Integer,
nullable=True,
),
)
따라서 직접 테이블에 접근할 수 없었다. 코드를 변경했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 기존 오류가 발생한 코드
association = models.naver_banner_image_instagram_post_association(
naver_banner_image_id=naver_banner_image.id,
instagram_post_id=post.id,
index=index,
)
db.add(association)
# 변경한 코드
stmt = insert(naver_banner_image_instagram_post_association).values(
naver_banner_image_id=naver_banner_image.id,
instagram_post_id=post.id,
index=index,
)
db.execute(stmt)