로컬에서 개발 시 사용하던 DB의 테스트 데이터를 잃고 싶지 않아서 db.sqlite3파일을 클라우드 폴더에서 링크하는 방법을 사용했는데, 이번에 PostgreSQL전용 필드를 사용하다보니 로컬 DB파일 자체를 백업하는 방식을 사용할 수 없어 자주 사용하는 runserver커맨드 실행시마다 자동으로 DB내용을 백업하도록 만들어 보았습니다.

Command를 등록할 app생성, management및 commands패키지 생성

Command만을 등록할 app을 생성합니다. app의 이름은 scripts를 사용합니다.

Terminal

python manage.py startapp scripts

그리고 생성된 scripts패키지에 아래와 같은 구조를 만듭니다.

Structure

<django project directory>/
  scripts/
    management/
      commands/
        __init__.py
        dump.py
        runserver.py
    __init__.py
  __init__.py    

INSTALLED_APPS에 scripts app추가

scripts app에 새로 정의한 커맨드가 기존 커맨드를 덮어씌우게 하기 위해 INSTALLED_APPS의 윗 부분에 앱을 추가합니다.

settings.py

INSTALLED_APPS = [
    'scripts',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

파일을 백업하는 dump.py모듈 작성

scripts/management/commands/dump.py

import subprocess

from django.conf import settings
from django.core.management import BaseCommand


class Command(BaseCommand):
    CMD = 'python manage.py dumpdata ' \
          '<공백으로 구분된 app이름> ' \
          '--indent=4 > ' \
          '<db파일을 저장할 경로>/db.json'

    def handle(self, *args, **options):
        process = subprocess.Popen(
            self.CMD,
            cwd=settings.BASE_DIR,
            shell=True,
            stdout=subprocess.PIPE
        )
        process.communicate()

CMD에 할당된 문자열을 셸에서 실행시킵니다.

runserver Command 재정의

scripts/management/commands/runserver.py

import subprocess

from django.conf import settings
from django.core.management.commands import runserver


class Command(runserver.Command):
    CMD = 'python manage.py dump'

    def handle(self, *args, **options):
        process = subprocess.Popen(
            self.CMD,
            cwd=settings.BASE_DIR,
            shell=True,
            stdout=subprocess.PIPE
        )
        process.communicate()
        super().handle(*args, **options)

원래 runserver커맨드가 하던 작업 앞에 이전에 정의한 dump명령어를 실행하도록 합니다.

마치며

python manage.py runserver또는 python manage.py dump를 실행할 때 마다 지정한 경로로 현재 DB파일의 내용을 백업합니다.

여러 토이 프로젝트를 진행하다보면 로컬 DB의 내용을 보관하는 작업이 조금 귀찮은데, 이번에는 기존 Command를 재정의하는 방법을 사용해봤습니다.