← Notes

Frappe Fixture — migrate마다 데이터를 덮어쓰는 시스템

general

개념

Frappe에서 fixture는 JSON 파일로 DB 레코드를 버전관리하는 시스템. bench migrate 할 때마다 JSON → DB로 동기화된다.

hooks.py에 fixture 선언 → bench export-fixtures로 JSON 생성
→ bench migrate 시 JSON → DB로 삽입/업데이트

설정 방법

hooks.py에서 선언:

# 전체 문서 export
fixtures = ["Email Template"]

# 필터로 특정 문서만
fixtures = [
    {
        "doctype": "Email Template",
        "filters": [["name", "in", ["invite", "welcome"]]]
    }
]
bench export-fixtures    # DB → JSON 파일로 추출
bench migrate            # JSON → DB로 동기화

파일 위치

앱이름/
  fixtures/
    email_template.json    # DocType 이름의 snake_case

JSON 안에 해당 DocType의 레코드들이 배열로 들어있다.

함정: UI 수정이 migrate에서 날아감

  1. UI에서 Email Template "invite"의 HTML을 수정
  2. bench migrate 실행
  3. fixture JSON의 원본 버전으로 덮어쓰기됨
  4. UI에서 수정한 내용 사라짐

이게 의도된 동작이다. fixture는 "이 데이터는 코드가 관리한다"는 선언이니까.

해결 패턴

1. fixture에서 제외

사용자가 UI에서 커스텀할 문서는 fixture에서 빼고, 초기 세팅은 after_install 훅으로 처리:

# hooks.py
fixtures = [
    {
        "doctype": "Email Template",
        "filters": [["name", "not in", ["invite"]]]  # invite는 제외
    }
]

2. fixture JSON을 수정

UI가 아니라 JSON 파일을 직접 수정하고 커밋. 이러면 migrate 후에도 최신 버전이 반영됨.

3. after_migrate 훅으로 조건부 생성

# hooks.py
after_migrate = ["앱이름.setup.create_default_templates"]
def create_default_templates():
    if not frappe.db.exists("Email Template", "invite"):
        # 없을 때만 생성, 있으면 건드리지 않음
        frappe.get_doc({...}).insert()

use_html 필드 주의

Email Template에는 responseresponse_html 두 필드가 있다.

  • UI에서 HTML 편집기로 저장하면 use_html=1 + response_html에 저장
  • fixture JSON은 보통 response 필드에 저장

코드에서 템플릿 본문을 읽을 때:

template = frappe.get_doc("Email Template", "invite")
body = template.response_html or template.response

response만 읽으면 UI에서 HTML로 작성한 내용이 무시된다.

정리

상황 방법
코드가 관리하는 데이터 fixture로 관리, UI 수정 금지
사용자가 커스텀하는 데이터 fixture에서 제외
초기값만 필요한 데이터 after_install/after_migrate로 조건부 생성
sunshinemoon · 2026