Django 특정 DB변경 판단하기

HS L·2023년 6월 19일
0

내일배움캠프

목록 보기
69/73
post-custom-banner

문제

이모티콘 상품화 관련 기능을 개발하는 중 특정 DB가 변경됐을 때 클라이언트에게 이메일 알림 기능을 도입하고자 했다.

현재 이모티콘 제작부터 상품화까지의 단계는 다음과 같다.

  1. 클라이언트의 제작 신청(Model instance Create)
  2. 신청 저장시 초기 db_status 필드는 0값으로 지정(신청 중 상태 / 상품 등록 이전에서만 Update, Delete 허용)
  3. 관리자의 검토 후 상품 등록(db_status값 0 -> 1 변경 / 판매 중 상태로 변경)
  4. 판매 중 상품 등록 이후 클라이언트의 수정 / 삭제 불가

위 과정에서 3번 단계인 신청 중 상태에서 판매 중 상태로 변경, 즉 상품화가 완료 됐을때 클라이언트에게 이메일 알림을 보내고자 했다.


시도

인스턴스의 수정이 이루어지는 단계에서 조건을 넣어줘야 할 것 같아 put 메서드에서 print문을 찍어봤다.

def put(self, request):
        emoticon = get_object_or_404(
        Emoticon, id=request.data.get("emoticon_id"), db_status=0
        )

        print(emoticon.db_status) 			# 수정 전 DB값

        if request.user == emoticon.creator:
            serializer = EmoticonSerializer(emoticon, data=request.data)
			...
            if serializer.is_valid():
                serializer.save()
			...

            	print(emoticon.db_status)	# 수정 후 DB값

                return Response(serializer.data, status=status.HTTP_200_OK)
            else:
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response(
                {"message": "수정 권한이 없습니다."},
                status=status.HTTP_403_FORBIDDEN
            )

db_status 수정을 진행했을 때 수정 전 DB값과 수정 후 DB값이 다르게 찍히는 것을 확인했다.

여기에 맞춰서 수월하게 마무리 되는가 싶었지만 역시나.. 그렇지 않지
admin페이지에서의 수정시에는 다른 url로 들어오는 요청이기 때문에 적용이 안되는 것을 발견했다.

클라이언트가 주가 되는 기능들은 프론트-백의 연결통로인 뷰 함수에서 처리해줘도 큰 문제가 없겠지만 지금 구현하고자 하는 기능은 관리자가 주가 되는 기능이다.

때문에 django의 장점 중 하나인 admin 페이지를 활용하기 위해 전역적으로 모델 필드의 DB변화를 판단하는 방법을 고민해봤다.

해결은 생각 외로 단순했다..
아래 해결 부분에서 서술하도록 하겠다.


해결

인스턴스의 필드값이 변하는 시점은 save()메서드의 실행이다.
이는 save()메서드가 DB변화를 판단하는 기준점이라는 것이다.

다시 말하자면, 전역적인 모델 필드의 DB변화를 판단하기 위해서는 판단기준이 되는 save()메서드를 오버라이딩 하면 가능해진다는 것이다.

save()메서드를 오버라이딩 할 때 수정됐을때만 적용될 수 있도록 추가적인 조건을 넣어줘야 한다.

해결된 코드는 다음과 같다.

class Emoticon(CommonModel):
    ...
    ...
    db_status_choice = [
        (0, "신청상태"),
        (1, "판매중"),
        (2, "판매중지"),
        (3, "신청삭제"),
    ]
	...
    ...
    def save(self, *args, **kwargs):
    	is_new = self.pk is None
        # 인스턴스가 존재하는지 확인(수정인지 확인)
        if not is_new:
            old_status = Emoticon.objects.get(pk=self.pk).db_status

        super().save(*args, **kwargs)

        if not is_new:
            if (old_status == 0) and (self.db_status == 1):
                # db_status가 신청상태에서 판매중으로 변경됐을때만 이메일 보내기
                print('테스트 성공')

상속하고자 하는 save가 실행되기 전 생성/수정 판단을 위해 "self.pk가 None인지"의 bool값을 변수에 담아줬다.

- if not is_new 대신 if self.pk로 작성하게 된다면 인자로 받는 self의 특성상 
save메서드가 실행된 이후에는 조건문을 만족하게 되면서 old_status를 
찾을 수 없다는 에러가 나게 된다. 
꼭 save메서드가 실행되기 이전의 값을 변수에 담아 저장하고 비교하자.

pk가 존재한다는 것은 수정이 진행될 것이라는 뜻이고 수정 전의 DB값을 저장하기 위해 변경 전 DB값을 old_status변수를 선언하여 담아줬다.

이후 save가 실행되면서 DB값의 변경이 생겼고 아래에서 변경 이전과 이후의 값을 사용하여 추가적인 조건을 넣어줄 수 있다.

profile
식이
post-custom-banner

0개의 댓글