default를 매번 생성하는 경우는 콜백 함수로서 건네준다는 기억

아무래도, 전회의 기사 후편을 사보하고 있는 월보인입니다.

이번에는 Django 사용이 API를 만들 때 대인기 DjangoRestFlamework (마이그레이션 DRF)에 대해,
조금 빠져 버렸지만 의외로 조사에 시간이 걸린 점을 tips로서 기사로 합니다.

조건은 다음과 같습니다.
  • 특정의 필드가 UNIQUE
  • 특정의 필드가 POST되지 않는 경우 디폴트치를 uuid로 넣고 싶다
  • API 엔드포인트는 api/test/

  • 사쿠와 샘플 프로젝트 만들기



    또한 DRF의 도입과 urls.py, settings.py 등의 설정은 생략합니다.

    api/models.py
    from django.db import models
    
    
    class TestModel(models.Model):
        code = models.UUIDField(unique=True)
    
        def __str__(self):
            return self.code
    

    api/views.py
    from rest_framework import viewsets
    from .models import TestModel
    from .serializer import TestModelSerializer
    
    
    class TestModelViewSet(viewsets.ModelViewSet):
        queryset = TestModel.objects.all()
        serializer_class = TestModelSerializer
    

    api/serializer.py
    import uuid
    
    from rest_framework import serializers
    
    from .models import TestModel
    
    
    class TestModelSerializer(serializers.ModelSerializer):
        code = serializers.UUIDField(default=uuid.uuid4())
    
        class Meta:
            model = TestModel
            fields = ('id', 'code')
    

    네, 이런 느낌입니다.
    이제 TestModel의 CRUD API를 만들었습니다.
    DRF는 신

    그러나 느낌이 좋은 분은 알아 차릴 것입니다.
    이 코드에는 치명적인 버그가 있습니다.

    우선 이동


    $ python manage.py runserver
    

  • http://localhost:8000/api 열기

  • Content를 비우고 POST

    uuid로 들어 있기 때문에 문제없는 것처럼 보인다.
    그래, 문제 없다고 생각했던 시기가 나에게도 있었습니다.
  • Content를 비우고 두 번째 POST


  • 맞습니다.
    두 번째는 UNIQUE 오류가 발생합니다.
    첫번째는 할 수 있었는데…

    원인



    api/serializer.py
    ...
    code = serializers.UUIDField(default=uuid.uuid4())
    ...
    
    uuid.uuid4() 라고 하는 기술을 해 버리는 것으로, runserver 시점에서 uuid가 생성되어 디폴트로 설정되어 버렸다.
    그래서이 경우 내부적으로

    api/serializer.py
    ...
    code = serializers.UUIDField(default='492e32fc-dce5-4ac7-b13d-0b3af0236f75')
    ...
    

    라는 동작이 되어 버렸습니다.
    생성 할 때마다 uuid 작성한다고 생각하는 사람 나 이외에도 있다고 생각한다 (해주세요)

    대책



    uuid.uuid4를 콜백 함수로 전달

    api/serializer.py
    ...
    code = serializers.UUIDField(default=uuid.uuid4)
    ...
    

    이렇게 하면 runserver 시점에서 code의 default는 uuid.uuid4 라는 콜백 함수를 가지기 때문에,
    하늘에서 등록할 때 콜백 함수가 달려, uuid가 생성되기 때문에 일건 낙착이라는 것이다.



    「알고 있는 것 같아 몰랐던 부분」, 「Document에 몰래 쓰여져 있는 것을 날려 버렸다」라는 문제는 엔지니어 있다고 생각한다.

    좋은 웹페이지 즐겨찾기