Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
817 views
in Technique[技术] by (71.8m points)

python - When to use Serializer's create() and ModelViewset's perform_create()

I want to clarify the given documentation of Django-rest-framework regarding the creation of a model object. So far I have found that there are 3 approaches on how to handle such events.

  1. The Serializer's create() method. Here is the documentation

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. The ModelViewset create() method. Documentation

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. The ModelViewset perform_create() method. Documentation

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

These three approaches are important depending on your application environment. But when do we need to use each create() / perform_create() function? On the other hand, I found some accounts that two create methods were called for a single post request the ModelViewSet's create() and serializer's create().

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  1. You would use create(self, validated_data) to add any extra details into the object before saving AND "prod" values into each model field just like **validated_data does. Ideally speaking, you want to do this form of "prodding" only in ONE location so the create method in your CommentSerializer is the best place. On top of this, you might want to also call external apis to create user accounts on their side just before saving your accounts into your own database. You should use this create function in conjunction withModelViewSet. Always think - "Thin views, Thick serializers".

    Example:

    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)
    
  2. The create(self, request, *args, **kwargs) function in the ModelViewSet is defined in the CreateModelMixin class which is the parent of ModelViewSet. CreateModelMixin's main functions are these:

    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()
    

    As you can see, the above create function takes care of calling validation on your serializer and producing the correct response. The beauty behind this, is that you can now isolate your application logic and NOT concern yourself about the mundane and repetitive validation calls and handling response output :). This works quite well in conjuction with the create(self, validated_data) found in the serializer (where your specific application logic might reside).

  3. Now you might ask, why do we have a separate perform_create(self, serializer) function with just one line of code!?!? Well, the main reason behind this is to allow customizeability when calling the save function. You might want to supply extra data before calling save (like serializer.save(owner=self.request.user) and if we didn't have perform_create(self, serializer), you would have to override the create(self, request, *args, **kwargs) and that just defeats the purpose of having mixins doing the heavy and boring work.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...