2026/01/02 MainProject - 20

김기훈·2026년 1월 2일

TIL

목록 보기
101/194

오늘 학습 내용 ✅

어드민 상세조회 과정 처리

  • 수강 신청(User) 흐름은 구현되어 있음
    • 하지만 관리자가 승인했을 때 실제로 수강생 데이터(CohortStudent)를 생성하는 로직이 누락
    • 그리하여 관리자가 수강 승인을 하더라도 CohortStudent 데이터가 생성되지 않기 때문에,
    • User 모델에 정의된 in_progress_cohortstudent 프로퍼티는 항상 None을 반환
  • 어제 과정이 안나온 이유
    • 실제 cohort_student 테이블에 데이터를 넣는 로직이 없었음
    • 코치님께서 추가해주시고 나서 바로 해봤는데 성공!
  • 답변쪽도 수정해야 하지만 답변기능이 아직 안나왔기 때문에 킵


내역 삭제

  • 질의응답 내역 삭제

    • 수강생들이 등록한 질의응답 내역을 삭제 가능
    • 조회된 질의응답 목록에서 항목을 선택하고 삭제하기 버튼을 클릭하여 삭제
    • 질의응답 상세 조회 모달 내에 위치한 삭제하기 버튼을 클릭하여 삭제
    • 질의응답 내역 삭제 시 해당 질문, 질문에 작성된 답변, 답변에 작성된 댓글들이 모두 함께 삭제
  • Django Admin은 기본적으로 delete_selected라는 "선택 항목 삭제" 액션을 제공

class Question(TimeStampedModel):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="questions")
    category = models.ForeignKey(QuestionCategory, on_delete=models.PROTECT, related_name="questions")
    title = models.CharField(max_length=50)
    content = models.TextField()
    view_count = models.BigIntegerField(default=0)
    
class Answer(TimeStampedModel):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,  # 작성자가 삭제되면 답변도 삭제
        related_name="answers",
        help_text="답변 작성자 ID",
    )

    question = models.ForeignKey(
        "qna.Question",
        on_delete=models.CASCADE,  # 답변이 속한 질문이 삭제되면 답변도 삭제
        related_name="answers",
        help_text="답변이 속한 질문 ID",
    )

class AnswerComment(TimeStampedModel):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,  # 작성자가 삭제되면 댓글도 삭제
        related_name="answer_comments",  # 유저입장에서 쓴 댓글들
        help_text="댓글 작성자 ID",
    )

    answer = models.ForeignKey(
        "qna.Answer",  # Answer 모델 참조
        on_delete=models.CASCADE,  # 댓글이 달린 답변이 삭제되면 댓글도 삭제
        related_name="comments",
        help_text="댓글이 달린 답변 ID",
    )
  • 기본 모델설정 자체가 질의응답 삭제시 질문,답변,댓글 싹다 삭제되기 때문에 굳이 할게 없음


  • 답변 삭제

    • 수강생들이 질문에 대해 작성한 답변을 삭제 가능
    • 질의응답 상세 조회 모달 내
      • 답변 목록에서 각 항목에 위치한 삭제버튼 ( x 아이콘

답변 추가

  • 아직 답변 기능이 구현되지 않았기 때문에 빠른테스트를 위해 답변은 목데이터로 처리한다.

목데이터(Mock Data)

  • 실제 데이터가 존재하지 않을 때, 테스트나 개발을 목적으로 진짜처럼 보이게 만든 가짜 데이터를 의미
  • 사용 목적

    • 독립적인 개발
      • 백엔드(BE)의 API 개발이 완료되지 않았더라도,
      • 프론트엔드(FE)에서 목데이터를 활용해 화면 UI를 미리 구현하고 테스트 가능
    • 다양한 상황 테스트
      • '데이터가 없는 경우', '데이터가 너무 많은 경우', '비정상적인 값이 들어온 경우' 등
      • 실제 환경에서 만들기 어려운 상황을 가짜로 만들어 검증 가능
    • 비용 및 보안
      • 실제 운영 중인 고객 데이터를 테스트에 사용하는 것은 보안상 위험하므로,
      • 이를 대체할 안전한 데이터가 필요

상세조회 문제

  • 프론트엔드 8기 조교 같이 현재 속한 코스와 기수를 출력해야하는데 그냥 "조교"만 나옴


프론트 요구사항

  • content_preview를 가져올때 content_preview가 태그까지 같이 가져옴
  • django.utils.html.strip_tags 유틸리티를 사용하면 HTML 태그를 쉽게 제거
[ 🔴 문제: 질문 목록(Question List) API를 호출했을 때, 프론트엔드에 전달되는 content_preview 필드에 <p>, <b>, <br>과 같은 HTML 태그가 그대로 포함되어 출력 ]


[ 🟡 원인: 에디터 등을 통해 저장된 본문 데이터(content)가 HTML 형식으로 DB에 저장되어 있었음 ]

기존 QuestionListSerializer에서 content_preview 필드를 단순히 serializers.CharField()로 정의하여, DB에 저장된 HTML 문자열을 아무런 가공 없이 그대로 클라이언트에 전달하고 있었음.

[ 🔵 해결: Django에서 기본으로 제공하는 django.utils.html.strip_tags 유틸리티를 사용하여 HTML 태그만 제거하고 순수 텍스트 추출 ]

content_preview를 가공하기 위해 serializers.SerializerMethodField()로 변경.

get_content_preview 메서드를 추가하여, 해당 필드 데이터가 반환되기 직전에 strip_tags()가 적용되도록 로직 구현.

검증 로직 마련: HTML 태그가 포함된 더미 데이터를 생성하여 API 응답 값에 태그가 존재하지 않는지 확인하는 테스트 케이스(test_question_list_content_preview_strips_tags) 작성 가이드 제공

새롭게 알게된 내용 ✅

오늘 발생한 문제(발생 했다면) ✅

[ 🔴 문제: 데이터 타입 불일치 (TypeError) ]
- `instance.trainingassistant_set.set([cohort])`를 사용할 때, 
  - `set()` 함수는 인자로 `TrainingAssistant` 모델의 인스턴스 리스트를 기대함
  - 하지만 기존 코드에서는 Cohort 객체를 직접 전달했기 때문에 
  - `"TrainingAssistant` 인스턴스가 필요한데 Cohort가 들어왔다"는 
  - 타입 에러가 발생하며 서버 500 오류가 발생

[ 🟡 원인: 모델 관계의 복잡성 ]
- 유저(User)와 기수(Cohort)는 직접 연결된 것이 아니라 TrainingAssistant라는 중간 모델을 
- 통해 1:1 또는 N:1 관계로 연결되어 있다. 
- 단순히 리스트를 교체하는 방식으로는 이 중간 매개 객체를 올바르게 생성하거나 수정할 수 없음

[ 🔵 해결: update_or_create 로직 적용 ]
- user=instance 조건을 통해 해당 유저가 이미 조교로 등록되어 있는지 확인
- 업데이트
  - 이미 데이터가 존재한다면 defaults에 설정된 cohort 정보만 최신 기수로 변경
- 생성
  - 만약 조교 데이터가 없다면 새로운 TrainingAssistant 레코드를 생성하여 유저와 기수를 연결
profile
안녕하세요.

0개의 댓글