최근 회사를 다니며 좋은 사수분 덕에 많은 Django 를 많이 배우고있다. 우리 회사에서는 Django 와 Graphene 을 사용하는데, 그 덕분에 Django 와 DRF 를 동일시 하던 사고 방식이 많이 깨진것같다. 원래도 할 줄은 알았지만, advanced 하게 사용하지는 못했던 것 같아서 반성하는 한편, 많이 배우고 있던 참이다.
개인 프로젝트를 진행하다보니 Django 와 DRF 의 경계가 더욱 명확하게 보였고, 그래서 더 명확히 코드를 작성하고 분리 할 수 있게 되었던것 같았다. 오늘은 그 내용들을 정리해 적어보려한다.
Signal
Django ORM 으로 DB 에 데이터를 저장하려고 한다. 그런데, 다음과 같은 상황이라면?
- 좋아요를 누를 때 그 좋아요 수를 올리는것과 같이 저장하려는 데이터가 저장 전에 일부 수정되어야 함
- View 에서 처리되기에 적절한 내용이 아님, 상술한 좋아요의 예시 처럼 해당 작업이 요청에 dependent 한게 아니라 모델에 dependent 함
두가지 방법을 생각 해 볼 수 있다.
- model 의 save 메소드를 Override
- Signal 의
pre_save
, 혹은post_save
를 활용
1번 방법은 직관적으로 사용 할 수 있을테니 생략하고, 이 단락에서는 Signal 에 대해서 이야기 해보고자 한다.
Django 에서 Signal 은 참으로 편리한 도구이다. 특정 작업을 실행하거나, 실행하기 전에 같이 호출 될 수 있다. 가장 대표적인건 pre_save
, post_save
인데 이 각각은 DB 에 값이 저장 직전
, 저장 후
에 실행될 작업을 지정 해 줄 수 있다.
그런데 이 Signal 을 남발 하는것은 좋은 패턴이 아니라고 한다. 대충 그 내용을 요약하자면, 코드가 쓸데 없이 길어지고, 관련한 로직임에도 불구하고 분리가 된다는것. 그래서 아주 제한적인 경우를 제외하고는 Signal 사용을 권장하지 않는다고 언급한 글에서는 말 하고 있다.
그렇다면 이 제한적인 경우는 어떤것들이 있을까?
- 3rd Party 라이브러리의 동작을 확장 할 때
- 내부 구조를 수정하지 않아도 되니까
- delete 와 함께 사용되는 Signal
- 하나의 object 나 여러개의 값을 지울 때 두가지 모두를 커버해서 좋음
- 하나의 Signal 을 여러 개의 모델에서 사용 할 때
- 다른 application 과의 dependency 를 줄이기 위해
- 가령 api 호출 같은것들이 있을듯, Signal 은 플러그인 같은 개념으로 이해하면 좋아서, 필요에 따라서 외부 어플리케이션에 의존성이 생길 경우 경우에 따라 해제 할 수 있어야 함
나는 개인 프로젝트에서 geocoding (주소 → 위경도, reverse 의 경우 위경도 → 주소) 관련 작업을 할 일이 있었다. 관련한 내용을 시그널로 분리해서 위치 관련 정보가 필요한 두개의 모델에서 모두 사용하도록 했었다.
주의 사항
Signal 은 동기적으로 작동하지만 특정 이벤트를 후킹(하는 것 처럼) 해 작동하기 때문에 어딘가(apps.py
)에 등록을 해줘야 한다. 그래서 나는 다음과 같이 등록을 했었는데
from django.apps import AppConfig
from django.db.models.signals import pre_save
class ReportConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.report'
def ready(self):
from apps.common.signals import geocode_pre_save_handler
from apps.report.models import Report
pre_save.connect(geocode_pre_save_handler, Report)
이것이다. 특이한점은 ready 메소드 안에서 임포트를 한다는것이다.
이유는 다음과 같다. Django 가 실행 되고, 연관된 모듈들이 실행되고 import 되며 [settings.py](http://settings.py)
에 있는 내용들이 반영된다. 그런데 문제는 이것이다. apps.py 들이 import 되는 시점은 settings.py 가 import 되기 전 시점이라 app 이 등록되지 않았다는 오류가 뜬다.
그러한 이유로 어떤 앱의 AppConfig 가 준비가 되면 실행 되는 메소드가 있는데, 그것이 ready 메소드이다. 그래서 이 안에 import 를 넣으면 ready 메소드가 실행이 될 때 import 가 된다. 그리고 저런식으로 Signal 을 connect 해주면 등록이 완료 된다.
'Computer Science' 카테고리의 다른 글
jest-puppeteer 를 사용하면 커버리지 측정이 안된다! (0) | 2022.01.13 |
---|---|
멋있는 사람 훔쳐보기: Tiangolo (FastAPI 개발자) (0) | 2021.09.11 |
Pytest 관련 짧은 팁 (0) | 2021.08.26 |
파이썬 함수가 mocking(patching) 이 안돼요! (0) | 2021.08.25 |
내 깃허브가 털렸다 (1) | 2021.04.09 |