Django가 다른 Polymorphic과 거동이 다른 건

Polymorphism



프로그래밍에는 Polymorphism이라는 생각이 있으며 Wkipedia에는 ​​다음과 같이 게재되어 있습니다. 링크

폴리모피즘(영어: Polymorphism)은 프로그래밍 언어의 형태 시스템의 성질을 나타내는 것으로, 프로그래밍 언어의 각 요소(정수, 변수, 식, 객체, 함수, 메소드 등)에 대해 그것들이 복수의 형태에 속하는 것을 용서한다는 성질을 가리킨다.

마찬가지로, 본래 RDB에서는 하나의 컬럼은 하나의 테이블에 대해서만 관계를 가지는 곳을, 복수의 테이블에 대해서 관계를 가지는 (복수의 형태에 속하는)와 같은 테이블을 Plymorphic Model이라고 합니다 .

SQL 안티패턴에서 소개된 폴리모픽 관련



SQL 안티 패턴 라는 책을 아십니까? RDB의 설계와 쿼리의 안티 패턴과 그 해결 방법을 소개 해설하고 있습니다.
그 중 폴리모픽 관련에 대해서도 해설이 있었으므로 샘플로서 소개합니다.



개요를 해설하면 Bugs(버그 기표) 테이블, FeatureRequests(기능 요망) 테이블이 있어, 각각에 Comments(코멘트)를 붙일 수 있다.
Comments의 issue_id는 Bugs의 bug_id, FeatureRequests의 requesst_id가 저장되고, 어느 테이블을 연결하고 있는지를 결정하기 위해 issue_type에 'Bugs'또는 'FeatureRequests'를 저장한다.

이때 실제로 발행되는 SQL이나 DB의 외래 키를 사용할 수 없는 것이, 버그등의 원인이 된다고 언급되고 있습니다.

장고 Polymorphic의 이상한 움직임



django-polymorphic과 Rails ActiveRecord를 비교하여 거동의 차이를 확인할 수 있습니다.
튜토리얼에 따라 각각을 구현하면 다음과 같습니다.

Rails



모델 파일
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
  belongs_to :
end

class Bug < ApplicationRecord
  has_many :comments, as: :commentable
end

class FeatureRequest < ApplicationRecord
  has_many :comments, as: :commentable
end

migration 파일
class CreateComments < ActiveRecord::Migration[5.0]
  def change
    create_table :comments do |t|
      t.string  :comment
      t.references :commentable, polymorphic: true
      t.timestamps
    end
  end
end

Craete와 Read
# Create
Bug.create(title: "bug", description: "hello")
FeatureRequest.create(title: "feature request", description: "hello")
Comment.create(comment: 'comment on Bug', commentable_type: 'Bug', commentable_id: 1)
Comment.create(comment: 'comment on FeatureRequest', commentable_type: 'FeatureRequest', commentable_id: 1)

# Read
Bug.first.comments.first
#<Comment id: 1, comment: "comment on Bug", commentable_type: "Bug", commentable_id: 1, created_at: "2019-09-22 15:55:44", updated_at: "2019-09-22 15:55:44">

FeatureRequest.first.comments.first
#<Comment id: 1, comment: "comment on FeatureRequest", commentable_type: "FeatureRequest", commentable_id: 1, created_at: "2019-09-22 15:55:44", updated_at: "2019-09-22 15:55:44">

장고


from django.db import models
from polymorphic.models import PolymorphicModel

class Comment(PolymorphicModel):
    id = models.BigAutoField(primary_key=True)
    comment = models.TextField()

class Bug(Comment):
    title = models.TextField()
    description = models.TextField()

class FeatureRequest(Comment):
    title = models.TextField()
    description = models.TextField()

Create 및 Read
# Create
Bug(comment='Bug', title="Bug title", description="Bug description").save()
FeatureRequest(comment='FeatureRequest', title="FeatureRequest title", description="FeatureRequest description").save()

# Read
Comment.objects.first()
# <Bug: Bug object (1)>

해설



Rails는 SQL 안티 패턴 예제의 테이블을 생성했습니다.
SQL 안티 패턴에서도 다루어지는 것처럼, Comment와 Bug, Comment와 FeatureRequest는 각각 외부 결합하지 않지만 ActiveRecord에 의해 그것을 의식하지 않아도 된다.
반면 Django의 PolymorphicModel의 동작은 완전히 다릅니다.
생성된 DB를 ER에 일으키면 다음과 같이 됩니다.



Bugs, FeatureRequest는 모두 comment_ptr_id에서 Comments와 결합되어 있습니다.
이것은 Bugs, FeatureRequest가 공통 속성 Comments를 상속 (inherit)하는 것 같습니다.
더욱 일대일의 관계가 되어 있기 때문에, 원래 했던 것은 더 이상 할 수 없습니다.

감상



Django의 PolymorphicModel은 SQL 안티 패턴으로 다루어지는 소위 폴리 모픽 관련과 완전히 다르다는 것을 알았습니다.
더 이상 PolymorphicModel과 다형성 관련이 다른 것을 가리키는? 심지어 느끼는 수준입니다.

좋은 웹페이지 즐겨찾기