Django migration 생성 원리, commands

LULLU·2022년 8월 24일
0

django

목록 보기
1/1

Migration이란?

Migrations

  • Django’s way of propagating changes of models into database schema.
  • Designed to be mostly automatic

Migrations Commands

  • makemigrations : model의 변경사항에 따라 새로운 migration파일을 생성
  • migrate : migration 파일을 db에 적용
  • sqlmigrate : 특정 migration이 실행하는 SQL 문 출력
  • showmigrations : migration 적용 상태 출력

How Django Detects Changes to Your Models

makemigrations

  • database schema를 inspect하지 않는다.
  • model의 이전과 definition 비교하는 방식도 아니다.

makemigrations의 실제 작동 방식

  1. 생성되어 있는 모든 migration 파일을 확인
  2. 현재 적용된 migration들로 current project state를 build
    • current project state : 적용된 migration들이 표현하는 실질적인 model의 상태
      • “이 migration들이 다 적용된 상태면, model은 이렇게 정의되어야 한다” 를 표현
      • class ProjectState
        # django/db/migrations/state.py
        class ProjectState:
            """
            Represent the entire project's overall state. This is the item that is
            passed around - do it here rather than at the app level so that cross-app
            FKs/etc. resolve properly.
            """
  3. current project state와 현재 model definition에 따른 has-to-be project state을 비교
  4. 두 state를 일치하게 만드는 operation list 생성
  • makemigrations code
    # django/core/management/commands/makemigrations.py
    class Command(BaseCommand):
        help = "Creates new migration(s) for apps."
    		...
        def handle(self, *app_labels, **options):
    				...
            # Load the current graph state. Pass in None for the connection so
            # the loader doesn't try to resolve replaced migrations from DB.
            loader = MigrationLoader(None, ignore_no_migrations=True)
            ...
            # Set up autodetector
            autodetector = MigrationAutodetector(
                **loader.project_state(),
                ProjectState.from_apps(apps),**
                questioner,
            )
            ...
            # Detect changes
            changes = autodetector.changes(
                graph=loader.graph,
                trim_to_apps=app_labels or None,
                convert_apps=app_labels or None,
                migration_name=self.migration_name,
            )
            ...
            self.write_migration_files(changes)
    # django/db/migrations/autodetector.py
    class MigrationAutodetector:
        """
        Take a pair of ProjectStates and compare them to see what the first would
        need doing to make it match the second (the second usually being the
        project's current state).
    		"""
    		...
    		def __init__(self, from_state, to_state, questioner=None):
            **self.from_state = from_state
            self.to_state = to_state**
            self.questioner = questioner or MigrationQuestioner()
            self.existing_apps = {app for app, model in from_state.models}
    
        def changes(self, graph, trim_to_apps=None, convert_apps=None, migration_name=None):
            """
            Main entry point to produce a list of applicable changes.
            Take a graph to base names on and an optional set of apps
            to try and restrict to (restriction is not guaranteed)
            """
            changes = self._detect_changes(convert_apps, graph)
            changes = self.arrange_for_graph(changes, graph, migration_name)
            if trim_to_apps:
                changes = self._trim_to_apps(changes, trim_to_apps)
            return changes

Reference

makemigrations

  • model의 변경사항에 따라 새로운 migration파일을 생성

Options

  • --dry-run :
    • migration 파일을 생성하지 않고, 어떻게 만들건지만 보여준다.
  • --dry-run --verbosity 3 :
    • migration.py 파일도 CLI에 출력해서 보여준다.

migrate

  • migration 파일을 db에 적용

Usage

  • migrate
    • 모든 app에 대해, 적용되지 않은 migration을 모두 적용한다.
  • migrate [app_name]
    • 지정한 app에 대해, 적용되지 않은 migration을 모두 적용한다.
  • migrate [app_name] [migration_number]
    • 지정한 app에 대해, 특정 migration으로 migrate를 한다. → migration을 특정 시점으로 돌릴 수 있다. (git checkout <commit_hash> 와 유사)

Options

  • --plan : migration을 실제로 실행하지 않고, 어떻게 실행될건지 보여준다.

Migration 적용 방식

  • Migration 적용 순서

    1. db에 SQL(DDL)을 보냄
    2. django_migrations에 migration 기록
  • 자세히 살펴보기

    Forward : migrate seminar 0004

    • migrate seminar 0004에 해당하는 sql 문

    • migration 상태를 기록하는 sql 문

    • django_migrations db table

    • migrate시 migration 대상 앱, 시점, 파일 이름을 포함한 migration 상태가 기록된다.

    • Q. 왜 migrate seminar 0004 에서 DROP DEFAULT를 추가로 실행할까?
      - non-nullable field에 default 값을 지정하지 않고, makemigration 실행

      # seminar/models.py
      class Seminar(models.Model):
      ...
      +++ type2 = models.CharField(
                           max_length=100, choices=(('A', '세미나'), ('B', '스터디')))

      1. DEFAULT ‘A’ : default값을 적용하여 row를 채우고
      2. DROP DEFAULT : 정의한 모델에는 column에 default값이 없으므로 다시 원래대로 돌려놓는 작업을 한다. (perserve_default=False에서 옴)

    Revert : migrate seminar 0003

    • django_migrations db table
      • revert 시 migration 기록 row도 삭제됨.

    Revert with dependency

    • seminar 0003까지 migrate된 상태에서 실행 결과…

      migrate seminar 0001 --plan

      migrate seminar zero --plan

      1. undo되는 migration이 dependency에 있는 migration을 우선하여 undo함.


        0002_user_seminars.py : seminar.0001_squashed~.py에 dependency가 걸려있다.

      2. 이후 최근에 적용된 migration 부터 역순으로 undo

0개의 댓글