본문 바로가기
개발

[sql, sqlalchemy] 연결된 두 테이블 cascade 설정하기 - 2 (uselist 설정)

by 박영귤 2023. 8. 10.

지난 글에서 문제점이 있었다.

class Announcement(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  title = db.Column(db.String(50), nullable=False)
  content = db.Column(db.Text, nullable=True)
  
class AnnouncementUrl(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  announcement_id = db.Column(db.Integer, db.ForeignKey('announcement.id', ondelete='CASCADE'), nullable=False)
  announcement = db.relationship('Announcement', backref=db.backref('urls', cascade='delete'))
  url = db.Column(db.Text, nullable=False)

Announcement 의 한 객체에서 announcement.urls로 접근하면 무조건 list로 반환을 해준다는 것이다. 예를 들어, announcement의 url이 3개가 있다면, [url객체1, url객체2, url객체3]으로 반환되고, 한 개만 있으면 [url객체1], 한 개도 없다면 []가 반환된다. 이는 1:N 관계에서는 유용할 수 있다. 하지만 1:1 관계에서는 아주 별로이다. 이를 방지하기 위해, db.relationship의 파라미터 uselist에 False값을 넘기면 된다. 하지만 AnnouncementUrl에 지정하는 것이 아니라, Announcement에 지정해주어야한다.

class Announcement(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  title = db.Column(db.String(50), nullable=False)
  content = db.Column(db.Text, nullable=True)
  urls = db.relationship('AcnnouncementUrl', backref=db.backref('announcement', cascade='delete'), uselist=False)
  
class AnnouncementUrl(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  announcement_id = db.Column(db.Integer, db.ForeignKey('announcement.id', ondelete='CASCADE'), nullable=False)
  url = db.Column(db.Text, nullable=False)

이렇게 하면 된다. 하지만, 이렇게 한다면 cascade가 작동하지 않게 되는 것을 발견했다.

이를 방지하기 위해 챗gpt에게 물어보았다.

backref가 아닌 다른 것을 사용하는 것을 볼 수 있다. 이대로 클래스를 만들어보았다.

class Announcement(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  title = db.Column(db.String(50), nullable=False)
  content = db.Column(db.Text, nullable=True)
  urls = db.relationship('AcnnouncementUrl', back_populates='knotice', cascade='all, delete-orphan', uselist=False)

class AnnouncementUrl(db.Model):
  id = db.Column(db.Integer, primary_key=True, autoincrement=True)
  announcement_id = db.Column(db.Integer, db.ForeignKey('announcement.id', ondelete='CASCADE'), nullable=False)
  announcement = db.relationship('Announcement', back_populates='urls')
  url = db.Column(db.Text, nullable=False)

이런 방식으로 작성하면 uselist = False이면서, cascade 특성을 이용할 수 있다.