Postgresql Secondary Table에 필드 추가하기

2024년 12월 24일 화요일

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)