何时使用序列化器的create()和ModelViewSet的perform_create()函数

146

我想澄清Django-rest-framework关于创建模型对象的给定文档。到目前为止,我发现有三种处理这种事件的方法。

  1. 序列化器的create()方法。这里是文档

class CommentSerializer(serializers.Serializer):

    def create(self, validated_data):
        return Comment.objects.create(**validated_data)
ModelViewset的 create()方法。 文档
class AccountViewSet(viewsets.ModelViewSet):

    queryset = Account.objects.all()
    serializer_class = AccountSerializer
    permission_classes = [IsAccountAdminOrReadOnly]
  • ModelViewset perform_create() 方法。文档

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

    这三种方法在您的应用环境中都很重要。但是什么时候需要使用每个 create() / perform_create() 函数呢?另一方面,我发现有些帐户为单个post请求调用了两个create方法,即ModelViewSetcreate()和序列化程序的create()

    2个回答

    190
    1. 在保存对象之前,您可以使用create(self, validated_data)方法将任何额外的细节添加到对象中,并像**validated_data一样为每个模型字段添加“prod”值。理想情况下,您希望只在一个位置进行此类“探测”,因此您的CommentSerializer中的create方法是最佳选择。除此之外,您可能还想在将账户保存到自己的数据库之前调用外部API来创建用户账户。您应该结合使用ModelViewSet中的create函数。始终记住 - “瘦视图,厚序列化器”。

      例如:

    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)
    
  • ModelViewSet 中的 create(self, request, *args, **kwargs) 函数是在 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)非常配合使用(其中可能包含您特定的应用程序逻辑)。

  • 现在您可能会问,为什么我们有一个只有一行代码的单独的perform_create(self, serializer)函数?!?这背后的主要原因是允许在调用save函数时进行自定义。您可能需要在调用save之前提供额外的数据(比如serializer.save(owner=self.request.user),如果我们没有perform_create(self, serializer),那么您将不得不覆盖create(self, request, *args, **kwargs),这只会破坏使用混合执行繁重和无聊工作的目的。


  • 1
    嗨!感谢您分享知识!关于序列化器中的 create(self, validated_data),它是指它专注于数据验证逻辑吗?而且它还能帮助将给定序列化器的数据返回到响应中,对吗? - Shift 'n Tab
    1
    现在,您已经通过了所有验证。我正在谈论的是,在将数据保存到数据库之前,您可能希望自定义经过验证的数据。我会在我的答案中举一个例子。 - Apoorv Kansal
    1
    没问题 - 我刚刚添加了一个例子以提供更多的上下文。 - Apoorv Kansal
    2
    那么这段代码 return models.YourModel.objects.create(email=email, **validated_data) 会保存数据到数据库中对吗? - Shift 'n Tab
    2
    因此,在序列化器中的create函数仅在执行serializer.save()时才会被调用。在AccountViewSet中的create(self, request)函数中,您根本没有调用serializer.save(),因此唯一的实例创建是通过此调用进行的:Account.objects.create_user(**serializer.validated_data) - Apoorv Kansal
    显示剩余9条评论

    9

    虽然Apoorv的答案是正确和非常详细的,这里是一个快速回答:

    • 当你想要更改对象创建时的“幕后”行为时,请重写perform_create()。例如,在对象创建之前或之后执行一些额外操作。
    • 当你想要修改响应时,请重写create()。例如,如果你想重新组织响应、添加额外的数据、额外的头信息等。

    6
    是指哪个 create() 方法?是序列化器(serializer)的还是模型视图集(ModelViewSet)的? - Haliax

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接