일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Prefetch_related
- nestedfunction
- 도커
- EC2
- dry-yasg
- database
- Transaction
- Continuous Delivery
- racecondition
- testcase
- DjangoCache
- apitestcase
- CI
- CD
- aws
- docker
- aggregate
- Python
- DRF
- Git
- annotate
- Coroutine
- to_attr
- QuerySet
- F객체
- 코루틴
- DjangoRestFramework
- Continuous Deployment
- 백준
- django
- Today
- Total
BackEnd King KY
TIL6 - django polymorphic 본문
Intro
객체지향을 공부하실 때 다형성은 많이 들어보셨을겁니다. 이 다형성이라는 단어를 영어로 바꾸면 바로 Polymorphic이 됩니다.
정확한 단어는 phism인데, 이 부분은 유도리있게 넘기도록 하겠습니다.
하나의 객체가 여러 가지 타입을 가질 수 있다는 뜻인데, 요즘 이 부분에서 문제가 생겨서 작업에 들어갈 예정입니다.
그래서 미리 공부할 겸 포스팅하게 되었습니다.
모든 출처는 공식문서입니다.
Polymorphic Start!
첫 번째로, django-polymorphic을 설치해줍니다.
pip install django-polymorphic
두 번째로, settings.py의 INSTALLED_APPS에 설치한 polymorphic을 추가해줍니다.
INSTALLED_APPS = [
...,
"polymorphic"
]
세 번째로 모델링을 해줍니다. 마이그레이션까지 해주는 거 잊지마세요!
from polymorphic.models import PolymorphicModel
class Project(PolymorphicModel):
topic = models.CharField(max_length=30)
class ArtProject(Project):
artist = models.CharField(max_length=30)
class ResearchProject(Project):
supervisor = models.CharField(max_length=30)
네 번째로 Shell_Plus를 켜서 데이터 생성 및 조회해보겠습니다.
Project.objects.create(topic="폴리모픽을 주제로한..")
ArtProject.objects.create(topic="예술프로젝트를 주제로한..", artist="아트록스")
ResearchProject.objects.create(topic="연구프로젝트를 주제로한..", supervisor="디지몬카이저")
그리고 프로젝트를 모두 가져오기 위해
Project.objects.all()
을 입력하면 ArtProject, ResearchProject까지 모두 조회됩니다.
A라는 모델을 B라는 모델이 상속받고, 각 모델마다 데이터를 한 개씩 만들었다면 A모델을 조회했을 때 B라는 모델도 A를 이용해서 만들었으므로 조회가 되는 것입니다.
이건 폴리모픽에 상관없이 해당하는 Django의 특징입니다.
Instance_of 와 not_instance_of를 이용하여 결과를 특정 하위 모델로 좁혀 값을 뽑을 수 있습니다.
이 두 메소드가 폴리모픽의 가장 큰 특징이며, 폴리모픽을 상속받지 않으면 위 두 메소드를 사용할 수 없습니다.
아래 이미지를 보면 Profile이란 모델을 Developer가 상속받게 만들은 뒤 테스트를 해봤는데, instance_of라는 특성이 없다고 나옵니다.
이렇게 폴리모픽을 설정한 모델이 없다면, filter를 타고 들어가거나, prefetch_related를 이용해서 접근해야 합니다.
하지만 폴리모픽이 설정되어 있다면 instance_of / not_instance_of를 이용해 연관된 데이터를 모두 뽑아낼 수 있는 것입니다.
데이터를 보니 instance_of, not_instance_of 모두 prefetch_related와 같은 느낌을 받았습니다.
기준 모델에 대해 SQL을 한 번 보여준 다음, instance_of에 들어간 모델에 대해 SQL이 호출되기 때문인데요.
첫 번째 발생한 SQL에서 polymorphic_ctype_id는 django_content_type에 저장된 ID를 불러옵니다.
왜 django_content_type의 id를 불러오냐면, import한 PolymorphicModel의 특성에 나와있습니다.
Polymorphic모델로 타고 들어가면 모델에 polymorphic_ctype이라는 컬럼이 있고, ContentType이라는 모델을 참조합니다.
ContentType으로 한 번 더 타고 들어가면 테이블명(db_table)이 django_content_type으로 설정되어 있는 걸 확인할 수 있습니다.
이렇게 모델이 연결되어 있기 때문에 django_content_type의 ID를 불러오게 되는 것입니다.
그리고 제 DB에 저장된 django_content_type의 17번은 instance_of에 들어간 ArtProject입니다.
Project에서 ArtProject로 접근하기 위해 where 조건에 추가되어 SQL이 나가는 것 같습니다.
Project에서 ArtProject로 접근할 수 있게 최초 쿼리에서 조건을 걸었으니, 그 다음 쿼리에서는 그에 맞는 ArtProject가 나오게 되는 것입니다.
그런데 여기서 prefetch_related와는 다른 점이, prefetch_related는 look_up에 해당하는 쿼리를 발생시키는데, 여기서는 기준이 되는 모델과 instance_of에 설정한 모델의 컬럼들이 모두 추출됩니다.
그리고 Join의 On 조건에서 보면 알 수 있듯이, ArtProject의 project_prt_id는 Project의 ID값이 됩니다.
instance_of 조금 더 파헤치기
그러면 여기서 instance_of에 여러 개 혹은 관련없는 모델이 들어간다면 어떻게 될까 궁금해졌습니다.
SQL을 보면 Inner Join을 통해 데이터가 절대 안나올 것 같지만 그래도 한 번 해봤습니다.
네 역시 Join 조건에서 걸러지게 되어 User 부분은 아무 데이터도 안나오게 됩니다.
not_instance_of는 이 모델은 제외하고 출력해달라는 뜻이어서 해당 모델만 제외하고 결과가 리턴됩니다.
마치며..
회사 내 코드 중 폴리모픽이 설정된 모델들이 있는데, 그렇다보니 서로 의존성이 너무 강해 폴리모픽 제거 작업을 하게 되었습니다.
물론, 혼자하는 게 아닌 팀원들과 함께 하게 되는데, MSA에 맞게 관리하기로 방향이 정해지면서 가장 먼저 최초로 하게 된 프로젝트(?)가 되었습니다.
화이팅!
'Django' 카테고리의 다른 글
TIL19 - Django Cache (0) | 2022.03.13 |
---|---|
TIL9 - PBKDF2 (0) | 2022.02.25 |
TIL5 - aggregate&annotate(2/2) (0) | 2022.02.18 |
TIL4 - aggregate&annotate(1/2) (0) | 2022.02.17 |
TIL3 - Django get_fieldname_display() (0) | 2022.02.16 |