레거시 시스템에 django로 다가가기 (1)
안녕하세요, 렌딧 Engineering 팀의 Jesse입니다.
앞으로 몇 편에 걸쳐, 어쩌다 django에 빠져들게 되었는지를 연재해보려 합니다.
- 1편 - Django를 도입하기 까지
- 2편 - Django inspectdb 튜닝하기
이 시리즈의 내용을 파이콘 한국 2018에서 발표 하였습니다. 아래 자료도 참고하세요.
렌딧에서는 다양한 서브 시스템들이 있지만, 그 중심에는 크고 거대한 Spring framework 기반 프로젝트가 있습니다. (렌딧의 기술 스택: ) 지금은 주로 (1%의 Kotlin과 함께) Java로 개발을 하고 있지만, 저도 한 때는 루비스트였는데요. 가끔은 Rails의 막강한 콘솔과 생산성이 그리웠습니다. 하지만 이미 수백 개의 모델(아니, 테이블이라고 하죠)을 가진 레거시 시스템을 재개발한다는 것은 엄두가 나지 않았습니다.
django를 만나다.
아….
나날이 RoR만 그리워하던 중, Integrating Django with a legacy database라는 글을 만나게 됩니다.
말 그대로, 레거시 DB만 있으면 단숨에 django 서비스를 만들어준다니 엄청나지 않습니까! 게다가 막강하기로 소문난 django admin까지 공짜로 얻을 수 있다니. 도저히 거부할 수 없는 제안이었습니다.
django에 레거시 DB 붙이기
붙이는 방법은 간단합니다. django 프로젝트 설정을 한 후,
1 | $ python manage.py inspectdb |
하면 모델 파일이 생깁니다. 생성되는 모델은 managed = False
로 설정되어, django가 테이블을 관리하지 않게 되니 기존 레거시 시스템도 운영해야 하는 환경에 딱 맞습니다.
레거시 시스템에서 새로운 테이블이 생겨나는 일도 종종 벌어지니, 아예 업데이트 스크립트도 만들어 두겠습니다.
1 |
|
2 | |
3 | set -e |
4 | |
5 | TEMP_FILE=models.py.tmp |
6 | MODEL_FILE=apps/core/models.py |
7 | |
8 | python manage.py inspectdb --database lendit \ |
9 | | tee $TEMP_FILE |
10 | |
11 | # model file에 바로 write하면 실행중인 코드가 변경되어 오류가 발생합니다. 임시파일을 거쳐서 생성합시다. |
12 | mv -f $TEMP_FILE $MODEL_FILE |
주의하실 점은, 이런저런 이유로 models.py가 생성이 제대로 안 되면 django 자체의 구동이 안된다는 점입니다. manage.py 자체가 동작하는데도 models.py가 필요하므로 진퇴양난의 상태가 될 수 있습니다.
django 어드민 붙이기
django 프로젝트를 만들어보셨다면 다 아실 부분입니다만, 다음과 같이 어드민을 등록해줍니다.
1 | from django.contrib import admin |
2 | from .models import * |
3 | |
4 | # Register your models here. |
5 | admin.site.register(LoanContract) |
6 | admin.site.register(User) |
7 | ... |
아… 장고 어드민도 완전 공짜는 아니고, 모델별로 register를 해줘야 하는군요! 저는 모든 테이블을 django 어드민에서 관리 하고 싶었기 때문에, 모든 모델에 대해서 admin.site.register()를 해주면 됩니다. (참 쉽죠?) 몇백줄만 쓰면 되겠네요.
네. 사실 이렇게 모델별로 수동으로 입력하는 것을 남겨두면 또 나중에 일일이 손으로 고쳐야겠지요. 강력한 파이썬의 모듈들을 사용하여 자동화해보자는 회사의 django 마스터 Sam Jo의 제안에 따라 아예 register()도 자동으로 되게 해봅시다. 여기서는 inspect
모듈을 사용해보겠습니다.
1 | # 예제 app 이름은 core입니다. 적절히 사용하는 이름으로 바꿔주세요. |
2 | modelClasses = [ |
3 | x[1] for x in inspect.getmembers(sys.modules["apps.core.models"], inspect.isclass) |
4 | if models.Model in x[1].__bases__ |
5 | ] |
6 | for modelClass in modelClasses: |
7 | admin.site.register(modelClass) |
이렇게 우리 모듈에서 model을 상속하는 모든 클래스를 어드민에 등록하였습니다.
짜잔~
django 어드민 고치기
어드민 상에서 CRUD도 할 수 있고, 신납니다. 그런데 기본 어드민만으로는 영 성에 안 차네요. 사용자 목록을 좀 보고 싶은데… User 모델을 누르면 다음과 같은 화면이…
당연히 모델에 대하여 알려준 게 없으니 적절히 표시하기가 힘들겠죠. 기본 어드민은 이렇게 object 라고만 알려주고, 검색도 안 되고, 보기도 힘듭니다. 어쩔 수 없이 이 부분은 코딩을 조금 해야 합니다. 드디어 django 코드를 짜는군요! 다시 어드민 파일을 엽시다.
1 | admin.site.unregister(User) |
2 |
|
3 | class UserAdmin(admin.ModelAdmin): |
4 | list_display = ('id', 'name', 'gender', 'phone') |
이미 위에서 일괄로 admin.site.register를 했기 때문에, 다시 unregister를 해줘야 된다는 점 주의하세요~
자주 보게 되는 주요 모델들에 대하여, 위와 같이 list_display
, search_fields
, list_filter
등을 설정해 주었습니다.
서비스 적용
이렇게 진짜 작성한 코드는 몇 줄 안 되는 날라리 어드민은 django 1.11.3과 함께 uWSGI에 실려 production 환경에 배포되었습니다.
아, AWS에서 저희가 사용하는 Amazon linux AMI에 pip로 일부 패키지가 잘 설치되지않아 어려움을 겪다가, django 마스터님의 도움으로 easy_install 시켰다는 비화가 있긴 하군요.
1편은 여기까지입니다. 2편에서는 레거시의 역습…아니 몇 가지 문제점 해결 및 inspectdb
기능에 대한 이야기를 해보려고 합니다.