개발

배포된 웹 사이트 새로운 모델 필드 추가하기

sungin95 2023. 6. 19. 17:23

지난번 모델을 수정하면서 몇가지 문제점이 드러났다. 

class Question(CommonModel):
    description = models.TextField()

    class Meta:
        abstract = True


# 공용 질문
class Questions(Question):
    authon = models.ForeignKey(
        "users.User",
        on_delete=models.CASCADE,
    )
    count = models.PositiveIntegerField(default=1)


# 개인 질문 모음
class SellectedQuestions(Question):
    user = models.ForeignKey(
        "users.User",
        on_delete=models.CASCADE,
    )
    importance = models.PositiveIntegerField(default=3)

Question을 공통으로 상속을 받으니까 ForeignKey를 따로 사용 안해도 된다고 생각했는데. 다른 유저들이 얼마나 선택했는지 알려주는 count의 값을 세기 위해서는 ForeignKey가 필요했다. 

 

데이터베이스를 삭제하고 다시 하는것이 편하겠지만, 실제 상황에서는 할 수 없는 방법이므로 기존의 데이터를 유지하면서 필드를 추가하는 방법에 대해서 고민을 해 보았다. 

새롭게 필드를 추가한 후 

class SellectedQuestions(Question):
    user = models.ForeignKey(
        "users.User",
        on_delete=models.CASCADE,
    )
    importance = models.PositiveIntegerField(default=3)
    question = models.ForeignKey(
        "Questions",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,  # 나중에 삭제
        related_name="questions_set",
    )

blank=True를 넣어서 빈칸으로 마이그레이션을 가능하도록 한다. 

 

그러면 현재 question은 빈 값이다. 

 

그리고 question에 값을 넣어줄 함수를 구현한다. (SQL문이 아니라 ORM을 활용한 이유는 for문을 돌리고 싶어서 입니다.) 

class ConnectQuestion(APIView):
    @transaction.atomic(using="default")
    def get(self, request):
        if request.user.is_staff == True:
            try:
                with transaction.atomic():
                    sellected_questions = SellectedQuestions.objects.all()
                    for sq in sellected_questions:
                        qs = Questions.objects.filter(description=sq.description)
                        # 1 값 넣어줌
                        if len(qs) == 1:
                            sq.question = qs[0]
                        # 2 없으면 None
                        elif len(qs) == 0:
                            sq.question = None
                        # 3 중복되면 에러 발생(롤백한다. )
                        else:
                            raise ParseError
                        sq.save()
                    return Response(status.HTTP_200_OK)
            except:
                pass
            return Response(
                {"message": "작업도중 에러 발생"}, status=status.HTTP_400_BAD_REQUEST
            )
        return Response({"message": "스태프가 아님"}, status=status.HTTP_403_FORBIDDEN)

1. views_admin.py이라는 새로운 페이지를 만들어 주었고 

2. if_staff 권한이 있는 사람만 작동 가능하도록 설정을 해 주었다. 

3. 트랜잭션을 사용하여 #3 description 가 중복되었을 시 일단 작업을 취소 하도록 만들었다. 

url

urlpatterns = [
    ......
    ......
 
    # admin
    path("admin", views_admin.ConnectQuestion.as_view()),
]

테스트 결과  이상 무~~~

 

 

원래 계획은 count도 변화를 주는 것이었는데. 막상 테스트를 해 보니까 count를 기준으로 정렬을 하고 있는데. 여기에 문제가 생겨서 count는 그대로 두기로 한다. 

 

이제 수정과 관련된 기능만 수정한 다음 배포된 서버에 등록하면 된다. 

로컬에서 서버용 MySQL을 연결해 준 다음 마이그레이션을 해 주고 

서버 백엔드 서버에 들어가 함수를 실행 시켜주어서 완료~

 

다행히 오류는 다 해결이 된거 같다~