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)
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).
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.
While Apoorv's answer is correct and very detailed, here's a quick answer:
perform_create()
when you want to change the "behind-the-scenes" behavior of how your object is created. For example, performing some extra actions before or after the object is created.create()
when you want to modify the response. For example, if you want to re-structure the response, add extra data, extra headers, etc.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With