Skip to content
Advertisement

When are create and update called in djangorestframework serializer?

I’m currently implementing djangorestframework for my app RESTful API. After playing around with it, I still do not clearly understand what .create(self, validated_data) and .update(self, validated_data) used for in the serializer. As I understand, CRUD only calls the 4 main methods in viewsets.ModelViewSet: create(), retrive(), update(), and destroy().

I also have already tried to debug and print out stuff to see when the .create() and .update() methods are called in both ModelViewSet and ModelSerializer. Apparently, only the methods in ModelViewSet are called when I do the HTTP verbs. However, for ModelSerializer, I don’t see any calls in those 2 methods. I just want to know what are those methods used for in ModelSerializer since I see that people override those methods a lot in the serializer.

Advertisement

Answer

You really must split things between the views and the serializer.

Serializers

The Serializer is a standalone object. It is used for converting a Django model (or any kind of python datastructure, actually) into a serialized form, and the other way around. You may use it as such, wherever you want. It does not even need an actual HTTP request as long as you don’t need URIs in your output.

The ModelSerializer subclass is a specialized kind of Serializer that adds “load-from-model” and “save-to-model” functionality. The “save-to-model” entry point is the save() method. For easier overriding, its default implementation will delegate its work to either the create() or update() method of the serializer, depending on whether it is creating a new model instance, or updating one.

The purpose of that is customization: it gives you, the developer, the option to override just the create method, just the update method, or common behavior. For instance, it allows you to do this kind of things:

def save(self, **kwargs):
    # Will be done on every save
    kwargs['last_changed'] = timezone.now()
    return super().save(**kwargs)

def create(self, instance, data):
    # Will only be done if a new object is being created
    data['initial_creation'] = timezone.now()
    return super().create(instance, data)

That’s a basic example. There, the last_changed field will be set every time an object is saved, be it a creation or an update. As a sidenote, you probably do not want to do that. Things such as setting “last_changed” fields should live in the view, not in the serializer.

Viewsets

In a completely different place, Django REST framework supplies Viewsets. Those are an organized collection of views, revolving around implementing a CRUD API for a model. As such, it structures it functionality into a set of methods, namely create(), retrieve()/list(), update() and delete().

The main point being: there is no connection whatsoever between the viewset’s create() method and the serializer’s create() method.

It just happens that the default implementation of the viewset’s methods uses a ModelSerializer and that the default implementation of that serializer’s save() method delegates the job to methods that have the same name.

By the way, about the last_changed example, here is how you would do it in the view:

def perform_create(self, serializer):
    now = timezone.now()
    serializer.save(initial_creation=now, last_changed=now)

def perform_update(self, serializer):
    serializer.save(last_changed=timezone.now())

That’s functionally equivalent to the example above, but lives in the viewset.

Conclusion

So back to your question, the specific thing you should override depends on which object is responsible for the task you want to add.

  • If your custom behavior is part of the serialization process, that is, the process of converting raw data back into a proper Django model and saving it, then you should override the Serializer‘s methods.
  • If, on the other hand, your custom behavior is specific to your viewset, then you should override the Viewset‘s methods.

As a hint, you may ask yourself the following question: if I use the same serializer in another place (maybe another viewset), should it always display that behavior?

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement