web-dev-qa-db-ja.com

Django Restフレームワークのsave()、create()、update()の違いは何ですか?

シリアライザーを使用してDjango RestフレームワークでAPIを作成するときに混乱します。save()、create()、update()メソッドの正確な違いを教えてください。私のコードサンプルは次のとおりです。

View.py

class AddUser(views.APIView):
    serializer_class = UserForAdminSerializer

    def post(self, request, *args, **kwargs):

        serializer = UserForAdminSerializer(data=request.data)

        if serializer.is_valid():

            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py

class UserForAdminSerializer(serializers.ModelSerializer):

    first_name = serializers.CharField(max_length=30)
    last_name = serializers.CharField(max_length=30)
    name = serializers.CharField(max_length=30)
    password = serializers.CharField(max_length=20, style={'input_type': 'password'})

    class Meta:
        model = User
        fields = ('id', 'url', 'first_name', 'last_name', 'name', 'username', 'email', 'password',
                  'total_exp_year', 'total_exp_month', 'voteup_count', 'is_featured',
                  'is_active', 'headline', 'description', 'profile_picture', )

    def create(self, validated_data):
        password = validated_data.pop('password', None)
        instance = self.Meta.model(**validated_data)
        if password is not None:
            instance.set_password(password)
        instance.save()
        return instance

上記のview.pyファイルのコードでは、save()メソッドとserializers.pyを使用してsave()またはupdate()メソッドを使用しているので、その動作を説明し、save()とcreate()の混乱を解消してください。

7
Ashok Kumar

通常、コードをよく理解するための最良の方法は、実際にコードを読むことです。そこで、 source を見てみましょう。

_class BaseSerializer(Field):
    ...
    def update(self, instance, validated_data):
        raise NotImplementedError('`update()` must be implemented.')

    def create(self, validated_data):
        raise NotImplementedError('`create()` must be implemented.')

    def save(self, **kwargs):
        ...
        ... a lot of assertions and safety checks ...
        ... 

        validated_data = dict(
            list(self.validated_data.items()) +
            list(kwargs.items())
        )

        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            ....
        else:
            self.instance = self.create(validated_data)
            ...
        return self.instance
_

さて、この基本クラスのメソッドでは、updatecreateは実装される具体的なサブクラスに任されています(詳細はListSerializerModelSerializerなどのシリアライザーによって異なるため)。

ただし、saveisが実装されており、基本的にはオブジェクトが新規か既存か(_if self.instance is not None_)をチェックし、それぞれupdateまたはcreateを呼び出します。 このコードは、他のすべてのシリアライザーで呼び出されます。

具体的なサブクラスを見てみましょう。

_def create(self, validated_data):
    ...
    ... some stuff happening
    ...

    try:
        # Here is the important part! Creating new object!
        instance = ModelClass.objects.create(**validated_data)
    except TypeError:
        raise TypeError(msg)

    # Save many-to-many relationships after the instance is created.
    if many_to_many:
        for field_name, value in many_to_many.items():
            set_many(instance, field_name, value)

    return instance


def update(self, instance, validated_data):
    raise_errors_on_nested_writes('update', self, validated_data)
    info = model_meta.get_field_info(instance)

    # Simply set each attribute on the instance, and then save it.
    # Note that unlike `.create()` we don't need to treat many-to-many
    # relationships as being a special case. During updates we already
    # have an instance pk for the relationships to be associated with.
    for attr, value in validated_data.items():
        if attr in info.relations and info.relations[attr].to_many:
            set_many(instance, attr, value)
        else:
            setattr(instance, attr, value)
    instance.save()

    return instance
_

ご覧のとおり、createupdateの両方を呼び出して、set_many(instance, attr, value)を呼び出してオブジェクト属性の値を設定します。ただし、createは、ModelClass.objects.create(**validated_data)の前に1つのcritical呼び出しを実行します。これにより、実際に新しいインスタンスが作成されます。

これで少しクリアになるといいのですが。

12
Siegmeyer

Django Rest Framework documentation では、saveメソッドをオーバーライドするタイミングとcreateメソッドをいつオーバーライドするかを非常に明確に説明しました。

私はあなたの便宜のために彼らの説明をここに投稿しています


場合によっては、.create()および.update()メソッド名が意味をなさないことがあります。たとえば、お問い合わせフォームでは、新しいインスタンスを作成するのではなく、メールやその他のメッセージを送信する場合があります。このような場合は、読みやすく意味のあるものとして、代わりに.save()を直接オーバーライドすることを選択できます。
例:-

class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()

    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)
5
Arpit Svt