Serializerのcreate()およびModelViewsetのcreate()perform_create()を使用する場合


101

django-rest-frameworkモデルオブジェクトの作成に関する特定のドキュメントを明確にしたいと思います。これまでのところ、このようなイベントを処理する方法には3つのアプローチがあることがわかりました。

  1. シリアライザーのcreate()方法。これがドキュメントです

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. ModelViewsetcreate()メソッド。ドキュメンテーション

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. ModelViewsetperform_create()メソッド。ドキュメンテーション

    class SnippetViewSet(viewsets.ModelViewSet):
    
        def perform_create(self, serializer):
            serializer.save(owner=self.request.user)
    

これらの3つのアプローチは、アプリケーション環境に応じて重要です。

しかし、いつ各create() / perform_create()関数を使用する必要がありますか??。一方、modelviewsetcreate()とserializerの単一のPOSTリクエストに対して2つのcreateメソッドが呼び出されたというアカウントを見つけましたcreate()

うまくいけば、誰かが説明するために彼らの知識のいくつかを共有するでしょう、そしてこれは確かに私の開発プロセスで非常に役立つでしょう。

回答:


130
  1. create(self, validated_data)AND "prod"値を各モデルフィールドに保存する前に、オブジェクトに詳細を追加するために使用**validated_dataします。理想的には、この形式の「プロディング」を1つの場所でのみ実行するため、create自分の方法がCommentSerializer最適な場所です。これに加えて、アカウントを独自のデータベースに保存する直前に、外部APIを呼び出してユーザーアカウントを作成することもできます。このcreate関数は、と組み合わせて使用する必要がありますModelViewSet。常に考えてください-「薄いビュー、厚いシリアライザー」。

例:

def create(self, validated_data):
    email = validated_data.get("email", None)
    validated.pop("email") 
    # Now you have a clean valid email string 
    # You might want to call an external API or modify another table
    # (eg. keep track of number of accounts registered.) or even
    # make changes to the email format.

    # Once you are done, create the instance with the validated data
    return models.YourModel.objects.create(email=email, **validated_data)
  1. create(self, request, *args, **kwargs)関数は、の親でModelViewSetあるCreateModelMixinクラスで定義されていModelViewSetます。CreateModelMixinの主な機能は次のとおりです。

    from rest_framework import status
    from rest_framework.response import Response
    
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
    def perform_create(self, serializer):
        serializer.save()
    

ご覧のとおり、上記のcreate関数は、シリアライザーで検証を呼び出し、正しい応答を生成します。この背後にある利点は、アプリケーションロジックを分離できるようになり、ありふれた繰り返しの検証呼び出しや応答出力の処理について心配する必要がないことです:)。これは、シリアライザーcreate(self, validated_data)(特定のアプリケーションロジックが存在する可能性がある場所)にあるものと組み合わせて非常にうまく機能します。

  1. さて、なぜperform_create(self, serializer)1行のコードだけで別の関数があるのか​​と疑問に思うかもしれません!?!?この背後にある主な理由は、save関数を呼び出すときにカスタマイズできるようにすることです。呼び出す前に追加のデータを提供することをお勧めしますsave serializer.save(owner=self.request.user)たとえばperform_create(self, serializer)、がない場合は、をオーバーライドする必要があります。これはcreate(self, request, *args, **kwargs)、ミックスインに重くて退屈な作業を行わせるという目的を損なうだけです。

お役に立てれば!


こんにちは!あなたの知識を共有してくれてありがとう!シリアライザーについてはcreate(self, validated_data)、データ検証ロジックに焦点を当てているということですか?さらに、特定のシリアライザーのデータを応答に戻すのに役立ちますか?
Roel 2016

1
いいえ、この時点では、すでにすべての検証に合格しています。データベースに保存する直前に、検証済みのデータをカスタマイズする方法について話します。私の答えに例を挙げます。
Apoorv Kansal 2016

1
心配はいりません-より多くのコンテキストを与えるために例を追加しただけです。
Apoorv Kansal 2016

1
ええ、それはあなたのオブジェクトをデータベースに保存する最後の行です
Apoorv Kansal 2016

1
したがって、createシリアライザー自体の関数は、実行したときにのみ呼び出されますserializer.save()。あなたにはcreate(self, request)、関数内部で(AccountViewSet)、あなたが呼び出しされていないserializer.save()すべてで、したがって、唯一のインスタンスの作成は、この呼び出しで起こっています:Account.objects.create_user(**serializer.validated_data)
Apoorv Kansal 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.