오늘도 개발

[2차 프로젝트 내일의 집] get_or_create 사용하기 본문

TIL & 프로젝트 회고

[2차 프로젝트 내일의 집] get_or_create 사용하기

Sueeeeeee 2022. 8. 3. 16:30

구현하고 싶은 것

유저의 kakao 아이디가 DB에 저장되어 있는 경우 => 추가 작업 없이 토큰 발행

유저의 kakao 아이디가 DB에 없는 경우 => DB에 새 유저 row 생성, 토큰 발행  

 

처음 생각한 코드

exists()로 유저 아이디가 DB에 있는지 확인하고

있으면 토큰 발급,

없으면 User.objects.create을 실행한다.

if User.objects.filter(kakao_id = kakao_id).exists():
    nhouse_token = jwt.encode({"user_id" : user.id}, settings.SECRET_KEY, settings.ALGORITHM)
    return JsonResponse({"message" : "LOGIN_SUCCESS", "access_token" : nhouse_token}, status=200)
else:
    User.objects.create(
        kakao_id      = kakao_id,
        email         = email,
        nickname      = nickname,
        profile_image = profile_image
    )
    nhouse_token = jwt.encode({"user_id" : user.id}, settings.SECRET_KEY, settings.ALGORITHM)
    return JsonResponse({"message" : "SIGNUP_SUCCESS", "access_token" : nhouse_token}, status=201)

 

get_or_create

원래 get_or_create는 race condition을 방지할 목적으로 나왔지만

여기에서는 코드를 간결하게 작성하기 위한 목적으로 사용할 수 있다.

 

get_or_create는 get을 실행한 뒤 튜플(오브젝트, True/False)을 반환한다.

get의 결과가 있으면 get의 결과를 오브젝트에 넣고, False를 반환한다.

get의 결과가 없으면 새로 생성해서 오브젝트에 넣고, True를 반환한다.

 

튜플의 두번째 값이 True인 경우에만 오브젝트에 값을 넣어 DB에 저장한다.

user, is_created = User.objects.get_or_create(kakao_id = kakao_id)
nhouse_token = jwt.encode({"user_id" : user.id}, settings.SECRET_KEY, settings.ALGORITHM)

if is_created:
    user.email         = email
    user.nickname      = nickname
    user.profile_image = profile_image
    user.save()

    return JsonResponse({"message" : "SIGNUP_SUCCESS", "access_token" : nhouse_token}, status=201)   

else:
    return JsonResponse({"message" : "LOGIN_SUCCESS", "access_token" : nhouse_token}, status=200)

 

리팩토링

하지만 위와 같은 방법으로 진행했을 때

- 이미 존재하는 유저의 정보를 가져오거나

- 없는 유저를 새로 저장하기만 가능하다.

이미 존재하는 유저의 nickname이 바뀐 경우 DB에 저장할 수 없다.

 

위 코드를 리팩토링해서 등록된 유저 정보가 바뀐 경우에 업데이트할 수 있게 만들었다.

또 defaults를 사용하면 더 가독성 있는 코드로 바꾸어보았다.

user, is_created = User.objects.get_or_create(
    # 장고는 defaults 바깥에 있는 항목을 사용하여 DB에 존재하는 오브젝트인지 확인한다.
    # 즉 아래 코드는 동일한 kakao_id와 email이 DB에 있는지 확인하고 get이나 create를 실행한다.
    kakao_id = kakao_id,
    email = email,
    defaults = {
        # DB에 없는 유저인 경우 defaults에 입력한 값으로 새 유저를 생성하고 DB에 저장한다.
        "nickname" : nickname,
        'profile_image' : profile_image
    }
)

nhouse_token = jwt.encode({"user_id" : user.id}, settings.SECRET_KEY, settings.ALGORITHM)

# DB에 존재하는 유저인 경우
if not is_created:
    # 프로필 이미지가 바뀌었으면 업데이트해서 저장한다.
    if not user.profile_image == profile_image:
        user.profile_image = profile_image
        user.save()
    # 닉네임이 바뀌었으면 업데이트해서 저장한다.
    if not user.nickname == nickname:
        user.nickname = nickname
        user.save()
    return JsonResponse({"message" : "LOGIN_SUCCESS", "access_token" : nhouse_token}, status=200)

return JsonResponse({"message" : "SIGNUP_SUCCESS", "access_token" : nhouse_token}, status=201)