앱별로 상세 설명을 진행하려고 하다가 큰 의미가 없는 것 같아서 프로젝트 진행하면서 기록하고 싶은 점이나 특징점을 쓰기로 하였습니다.
□ TimeStampedModel
class TimeStampedModel(models.Model):
updated_datetime = models.DateTimeField(auto_now=True)
created_datetime = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
대부분의 모델에서 생성일과 수정일 필드는 존재하기 때문에 추상클래스 TimeStampedModel을 상속받아 모델들을 생성하였습니다.
추상클래스 TimeStampedModel을 상속받은 휴대폰인증 이력 모델
class PhoneVerificationHistory(TimeStampedModel):
phone_number = models.CharField(max_length=11)
verification_code = models.CharField(max_length=6)
is_verified = models.BooleanField(default=False)
uuid = models.UUIDField(default=uuid.uuid4, editable=False)
□ API View를 만드는 여러가지 방법
아래 코드는 휴대폰 인증코드를 보내는 API입니다.
(1) 데코레이터를 이용하여 api_view 이용
@api_view(["POST"])
@permission_classes([AllowAny])
def send_verification_code(request):
if request.method == "POST":
serializer = PhoneVerificationHistoryCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)
(2) 클래스로 APIView 이용
class VerificationCodeSender(APIView):
permission_classes = [AllowAny]
def post(self, request):
serializer = PhoneVerificationHistoryCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
(3) Generic APIView 이용
class VerificationCodeSender(generics.CreateAPIView):
permission_classes = [AllowAny]
serializer_class = PhoneVerificationHistoryCreateSerializer
(4) GenericViewSet + CreateModelMixin 이용
class VerificationCodeSender(viewsets.GenericViewSet, mixins.CreateModelMixin):
permission_classes = [AllowAny]
serializer_class = PhoneVerificationHistoryCreateSerializer
http_method_names = ["post"]
처음에 DRF를 접했을 때 하나의 HTTP Method만 사용할 경우, 그냥 무조건 api_view 데코레이터((1)번 방식)를 사용했었습니다. 그 땐 익숙하지도 않았고 그게 제일 쉬워보였거든요. 그런데 쓰다보니 (3), (4)번처럼 DRF에서 제공해주는 것들을 잘 이용하면 반복된 코드를 제거할 수 있고, 코드가 깔끔해지는 경우가 많았습니다. 물론 구현하려는 기능이 복잡하거나 커스텀이 필요할 경우, 그대로는 못쓰고 오버라이딩하여 사용해야겠죠.
□ ModelSerializer 사용
휴대폰인증 이력 생성 관련 Serializer 코드
class PhoneVerificationHistoryCreateSerializer(serializers.ModelSerializer):
class Meta:
model = PhoneVerificationHistory
fields = ["phone_number"]
extra_kwargs = {
"phone_number": {"write_only": True},
}
DRF 직렬화 속도 비교를 보면 아래와 같습니다.
Regular Serializer (Read Only) > Regular Serializer > ModelSerializer (Read Only) > ModelSerializer
무조건 속도만 생각하면 ModelSerializer를 사용하면 안되지만 채팅 메시지처럼 여러 건이 아닌 단 건의 데이터만 다루고 있을 경우, ModelSerializer를 사용하였습니다.
□ Tiny Function
다음 나오는 코드는 휴대폰 인증번호 생성할 때, 사용되는 함수입니다.
def get_random_verification_code() -> str:
return f"{random.randint(100000, 999999)}"
위와 같은 매우 작은 함수는 Clean Code에서는 선호하는 방향이지만 Python에서 이런 작은 함수를 자주 사용하는 것은 56%의 속도 저하를 일으킨다고하는데 상황에 따라 적절히 사용해야할 것 같네요.
https://www.youtube.com/watch?v=YY7yJHo0M5I
□ Regex compile cache
인증번호 6자리를 regex로 검사하는 코드
# 인증번호 숫자 6자리 regex로 검사
def validate_verification_code(self, value):
regex = re.compile(r"^\d{6}$")
if regex.search(value):
return value
else:
raise serializers.ValidationError("입력된 인증코드의 형식이 잘못되었습니다. 숫자 6자리를 입력해주세요.")
처음 regex compile하는 부분에서 속도에 영향미치는 것이 아닌가하고 알아봤더니 해당 부분은 재호출되어도 캐시되기 때문에 전역적으로 보관하지 않아도 괜찮다고 합니다.
'Project > [Project] Red Horse' 카테고리의 다른 글
[Backend] 정리 - 3 (0) | 2023.06.15 |
---|---|
[Backend] 정리 - 2 (0) | 2023.06.14 |
[Backend] env 환경변수 (0) | 2023.06.12 |
[Backend] 프로젝트 환경셋팅 (0) | 2023.06.12 |
[Backend] API 설계 (0) | 2023.06.09 |