카테고리 없음

Django + DRF Valid를 거칠 때 동시에 저장을 하는 방법

khw7876 2022. 9. 2. 18:31

Service Layer를 사용하여서 표현 하였다.

가령 이런 상황이 있을 것이다.
Serializer를 이용하여서 하나의 파일을 저장을 하거나 수정을 한다.
그리고 그 파일이 성공적으로 저장, 수정이 된다면 추가로 그에 대한 로그를 저장하는 상황 말이다.

그렇다면 여기서 어떠한 문제점이 숨어있을 수 있을까?

- 예외사항

-    첫번째 파일이 성공적으로 저장이 되었는데, 두번째로 저장하는 로그에서 에러가 발생할 경우
-    이렇게 된다면 첫번째로 실행되는 로직만이 저장이 되고, 두번째 로직은 저장이 되지 않는다.
-     벌써부터 에러상황이 생기는 것이다.

- 그렇다면 어떻게 해결할 수 있을까?

Serializer를 이용하여 저장 및 업데이트를 할 때에는 is_valid()함수를 꼭 거쳐야한다.
그런데 여기서 is_valid()함수 안에 raise_execpt = True를 넣어주게되면 발생한 에러에 대해 어떠한 에러인지를 내뱉어준다.

그리고 Save()가 되기 전에 검증만을 해주는 것이다!

무슨 말인가?

기존의 방식

  • 1번함수 검증
  • 1번함수 저장
  • 2번함수 검증
  • 2번함수 저장

이러한 로직으로 인하여 1번함수가 성공적으로 저장이 되었을지라도 2번함수를 검증을 하는 단계에서 Error가 발생하여 저장이 안될 수 있다는 것이다.

그렇다면 이렇게 생각해보자

순서를 바꾼다.

  • 1번함수 검증
  • 2번함수 검증
  • 1번함수 저장
  • 2번함수 저장

이렇게 로직을 짠다면, 모든 검증이 끝난 후 저장이 이루어지기에 하나라도 에러가 발생한다면 둘 다 저장이 되지 않는다.
만약 둘 다 정상적으로 에러없이 통과했다면, 둘 다 저장이 되도록 할 수 있다.

이것을 로직으로 살펴보도록 하자.

def update_post(user : int, post_id : int, update_post_data : Dict[str, str])-> Dict[str, Union[PostSerializer, PostUpdateLogSerializer]]:
    """
    모든게시판의 Update를 담당하는 Service
    update_post에 대한 검증이 이루어지면 update_log를 생성하는 함수에 대한 검증 실행
    두개 모두의 검증이 끝나야 저장
    Args :
        user (UserModel): user.User 외래키 (request.user를 통해 로그인한 유저 반환),
        post_id (int): posts.Post 외래키, url에 담아서 보내줌,
        update_post_data (dict): {
            "title" (str): 게시글의 제목 or
            "content" (str) : 게시글의 내용
        }
    Return :
        dict[str, Union[PostSerializer, PostUpdateLogSerializer]]
    """
    log_data = {"user" : user.id, "post" : post_id}

    update_post = PostModel.objects.get(id=post_id)
    update_post_serializer = PostSerializer(update_post, update_post_data, partial=True)
    update_post_serializer.is_valid(raise_exception=True)

    post_update_log_serializer = PostUpdateLogSerializer(data=log_data)
    post_update_log_serializer.is_valid(raise_exception=True)

    update_post_serializer.save()
    post_update_log_serializer.save()
    return (
        {"update_post" : update_post_serializer.data}, 
        {"update_log" : post_update_log_serializer.data}
        )

update_post_serializer에 대한 검증,

post_update_log_serializer 에 대한 검증

이렇게 두개의 서비스 로직을 합침으로서 Error를 핸들링 할 수 있게 되었다.