250109 TIL 모델 간 순환 참조 문제, TestPlan 생성 로직
1. 한 일
Django 모델 간 순환 참조 문제 해결
- Django의
OneToOneField를 사용하여 ChatRoom과 TestPlan 간 1대1 관계를 설정했다.
- 순환 참조 문제를 방지하기 위해 모델 참조를 문자열(
"app_name.ModelName")로 변경하여 초기화 순서를 유연하게 조정했다.
unique_together를 사용하여 각 chat_id별로 plan_id가 고유하도록 데이터 무결성을 설정했다.
TestPlan 생성 로직 구현
- 사용자의 메시지(예:
"이제 계획을 세워줘")를 기반으로 자동으로 TestPlan을 생성하고 ChatRoom과 연결하는 로직을 구현했다.
TestPlan 생성 시, plan_id를 pre_save 신호를 통해 자동 증가하도록 설정했다.
transaction.atomic()과 select_for_update()를 사용하여 동시성 문제를 방지하고, 데이터의 무결성을 유지했다.
API 설계 및 예외 처리
TestPlanCreateView를 작성하여 POST /chatroom/<chat_id>/testplan/ 요청으로 TestPlan을 생성하고 ChatRoom과 연결하는 기능을 구현했다.
- 예외 처리:
- ChatRoom.DoesNotExist 예외 발생 시 404 응답 반환.
- 이미 TestPlan이 존재할 경우 400 응답으로 처리.
2. TroubleShooting
순환 참조 문제
- 오류 메시지:
ImportError: cannot import name 'TestPlan' from partially initialized module...
- 원인: ChatRoom과 TestPlan 모델이 서로를 참조하면서 초기화 순서 문제가 발생.
- 해결:
- 모델 참조를 문자열로 변경하여 순환 참조 문제를 해결.
- TestPlan의 chat_id와 ChatRoom의 testplan 필드 모두 "app_name.ModelName" 형식으로 참조하도록 수정.
plan_id 설정 문제
- 문제: 새로운
chat_id에 대한 첫 번째 TestPlan 생성 시, select_for_update()가 작동하지 않음.
- 원인: 데이터베이스에 기존 데이터가 없으면 잠금을 설정할 대상이 없음.
- 해결:
pre_save 신호에서 TestPlan.objects.filter(chat_id=...)를 사용해 데이터가 없을 경우 plan_id=1로 설정.
transaction.atomic()으로 동시성 문제를 방지.
테스트 데이터 저장
- 오류 메시지:
TypeError: Object of type ChatRoom is not JSON serializable
- 원인: ChatRoom 객체를 JSON 응답으로 직접 반환하려 했기 때문.
- 해결: ChatRoomSerializer를 사용하여 데이터를 JSON으로 변환 후 반환.
3. 느낀 점
Django 모델 관리
- 모델 간 참조는 문자열로 작성하면 초기화 순서 문제를 방지할 수 있다는 점을 배웠다.
OneToOneField를 사용해 1대1 관계를 명확히 정의하고, 데이터 무결성을 보장하는 설계가 중요함을 깨달았다.
데이터 무결성과 트랜잭션
transaction.atomic()과 select_for_update()를 통해 동시성 문제를 방지하고, 데이터의 무결성을 유지하는 방법을 익혔다.
unique_together를 사용하면 간단히 필드 간 고유성을 보장할 수 있다는 점도 유용했다.
API 설계
POST 요청으로 특정 ChatRoom에 연결된 TestPlan을 생성하고 관리하는 RESTful 설계의 중요성을 경험했다.
- 적절한 예외 처리가 API의 안정성과 사용자 경험을 크게 향상시킨다는 점을 배웠다.