Skip to content

feat(exporter): Django 백엔드 - #198

Open
yyuneu wants to merge 12 commits into
dev-five-git:mainfrom
yyuneu:django-exporter
Open

yyuneu wants to merge 12 commits into
dev-five-git:mainfrom
yyuneu:django-exporter

Conversation

@yyuneu

@yyuneu yyuneu commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

#169에서 Django 백엔드 관련 변경 사항만 분리한 PR입니다. #197(GORM) 위에 쌓여 있으므로, #197가 머지되기 전까지는 diff에 #197 의 커밋도 함께 표시됩니다. 리뷰는 뒤쪽 6개 커밋만 확인해 주시면 됩니다. #197 가 머지되면 diff에는 해당 6개 커밋만 남습니다.

작업은 @2heunxun 님이 시작하셨으며, 중간부터 제가 이어받았습니다. 첫 커밋은 해당 작성자의 Django 구현을 upstream과 병합한 상태 그대로이며, 작성자 정보도 유지했습니다. 이후 5개 커밋이 제가 진행한 작업입니다.

#169 리뷰 반영

  • app_label 설정은 유지했습니다. app_labelINSTALLED_APPS에 등록된 앱에 의해 결정되므로, 폴더 이름으로 추론하면 잘못된 값이 조용히 설정될 수 있습니다. 다만 export 디렉터리가 Django 앱 디렉터리인 경우에는 Django가 직접 추론하므로 일반적으로 별도 설정이 필요하지 않습니다. 설정하지 않으면 Meta에도 아무것도 출력하지 않습니다. config에 남는 ORM 관련 항목은 이것 하나입니다.
  • Django enum의 라벨 인자를 제거했습니다. 원값을 라벨로 전달하면 Django가 멤버 이름에서 자동 생성하는 라벨(PENDING → "Pending")보다 적절하지 않은 값이 고정됩니다.
  • 테스트 전용 re-export를 제거하고, 테스트를 #[cfg(test)] mod tests 내부로 옮겼습니다.

CLI 출력

vespertide export --orm django는 전체 스키마를 단일 models.py 파일로 출력합니다.

Django는 앱의 모델을 models 모듈에서 읽으므로, 테이블별로 파일을 나누면 __init__.py에서 모두 import하지 않는 한 모델이 등록되지 않습니다.

startapp이 생성한 기존 models.py를 삭제하지 않도록, 생성 표식으로 시작하지 않는 파일은 덮어쓰지 않고 에러로 알립니다.

모델은 managed = False로 출력합니다. DDL은 vespertide가 소유하므로, makemigrations가 해당 테이블을 생성하거나 변경해서는 안 됩니다.

Django 출력에서 수정한 사항

작업을 이어받은 후 생성물을 Django 6.1 시스템 체크에 넣고, vespertide가 생성한 DB에서 실제 삽입·조회를 검증하는 과정에서 여러 출력 문제를 확인했습니다.

수정한 내용은 다음과 같습니다.

대상 수정 사항
시스템 체크 _로 시작하는 모델명(models.E023), 필드에서 사용할 수 없는 on_delete(fields.E320·E321), 복합 PK 모델로의 관계(fields.E347·E336), unique가 아닌 컬럼을 참조하는 FK(fields.E311), FK의 attname과 이름이 겹치는 컬럼(models.E006), 30자를 초과하는 인덱스 이름(models.E034), 모델 자체 속성과 이름이 겹치는 필드(check·save·objects·Meta 등), callable이 아닌 JSONField 기본값(fields.E010)
조인 PK가 아닌 컬럼을 참조하는 FK에 to_field가 누락되어 Django가 조용히 PK로 조인하던 문제를 수정했습니다.
관계 unique·PK인 FK는 OneToOneField로 출력하고, 복합 PK 정션은 ManyToManyField(through=…)로 처리합니다. 복합 FK와 복합 키 모델로의 FK는 컬럼과 주석으로 출력합니다.
이름 하나의 모듈에 전체 스키마가 들어가므로 모델·choices 클래스 이름을 모듈 단위에서 한 번만 점유하도록 변경했습니다(GORM과 동일한 scope_names.rs). 필드·멤버 이름은 Python 키워드, Django 필드 체크, __ name mangling을 통과하도록 처리했습니다.
JSONB는 JSONField로 출력하고, 문자열 기본값의 SQL 이스케이프('it''s'"it's")와 설명·컬럼명·enum 값에 포함된 "·\의 이스케이프를 처리했습니다.

다른 백엔드에 영향을 주는 변경

기존 스냅샷은 변경되지 않았습니다. 출력이 달라지는 경우는 지금까지 fixture가 없었던 입력에 한정됩니다.

  • SQLAlchemy·SQLModel: Python 키워드인 컬럼명은 속성명에 _를 붙여 출력합니다(fromfrom_). DB 컬럼명은 그대로 전달합니다. 기존에는 Python 문법 오류가 발생하던 출력입니다. Django의 필드명 처리와 동일한 헬퍼를 사용하므로 이 PR에 포함했습니다.
  • SQLAlchemy·SQLModel·Django 공용 enum 멤버 이름: __로 시작하는 이름은 Python name mangling의 대상이므로 _ 하나로 줄입니다.
  • SeaORM: 정션 판정을 constraint_scan::junction_targets로 분리하여 Django와 공용으로 사용합니다. SeaORM의 기존 호출부 2곳을 교체했으며, 출력은 동일합니다.

테스트

모듈별 스냅샷과 contains() 테스트를 공용 8-ORM 스냅샷으로 통합했습니다(전체 646개).

이 PR에서 추가된 스냅샷은 Django 출력 79개와, Django 구현을 계기로 추가한 fixture 4개(파이썬 예약어, 복합 키 정션, M2M 이름 충돌 2종)에 대한 다른 ORM 출력 28개입니다.

CLI에는 Django 출력 스냅샷 2개를 추가했습니다.

검증

검증 항목 결과
fmt, clippy(-D warnings), 전체 테스트, line-budget, schema-gen 무변경, cargo-deny 모두 통과
동일한 커밋을 제 포크의 PR에서 실행 CI 전체 잡(coverage 100%, changepacks, semver-checks 포함), mutation 16개 샤드, benchmarks 통과
Django 6.1 시스템 체크 examples/app(모델 11개)과 오류가 발생하기 쉬운 입력만 모은 스키마 모두 메시지 0건. 단일 테이블 스냅샷에는 파일 외부 모델을 참조하여 발생하는 메시지만 남습니다.
런타임 vespertide가 생성한 SQLite DDL로 DB를 구성하고 Django ORM으로 삽입·조회했습니다. 자연키 FK 조인, one-to-one, self-reference, 복합 PK 정션과 M2M, CHECK, ON DELETE, attname 충돌, 기본값을 확인했습니다.

현재 이 PR의 워크플로는 승인 대기(action_required) 상태입니다. 실행을 승인해 주시면 감사하겠습니다.

미리 말씀드릴 사항

  • Meta.indexesname=은 SQL 계층이 생성한 이름(ix_{table}__{key})이 30자 이내인 경우에만 사용합니다. managed = False이므로 Django가 해당 인덱스를 생성할 일이 없어, 30자를 초과하면 이름을 지정하지 않습니다.
  • JSONField에는 기본값을 출력하지 않습니다. Django는 callable만 허용하며(fields.E010), SQL 리터럴은 문서에 저장된 텍스트이므로 실제 값으로 사용할 수 없습니다. Django는 INSERT 시 항상 값을 전달하므로, 이 컬럼의 값은 호출자가 직접 지정해야 합니다. DB 기본값을 그대로 사용하도록 하는 db_default 렌더링은 후속 작업으로 남겨두겠습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants