LoginSignup
5
2

More than 5 years have passed since last update.

defaultを毎回生成する場合はコールバック関数として渡すという覚え書き

Last updated at Posted at 2018-11-01

どうも、前回の記事後編をサボっている月歩人です。

今回は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
  1. http://localhost:8000/api を開く スクリーンショット 2018-11-01 22.22.52.png
  2. Contentを空にしてPOSTする スクリーンショット 2018-11-01 22.24.33.png uuidで入っているので問題なさそうに見える。 そう、問題ないと思っていた時期が私にもありました。
  3. Contentを空にして2回目のPOST スクリーンショット 2018-11-01 22.26.46.png

そうです。
2回目はUNIQUEエラーになってしまうのです。
1回目はできたのに…

原因

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が生成されるので一件落着ということだ。

スクリーンショット 2018-11-01 22.34.53.png


「知っているようで知らなかった部分」、「Documentにひっそり書かれている事を飛ばしてしまいハマった」という問題はエンジニアあるあるだと思う。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2