44👍
Usually the best way to get a good understanding of the code is to actually read it, so let’s take a look at the source:
class BaseSerializer(Field):
...
def update(self, instance, validated_data):
raise NotImplementedError('`update()` must be implemented.')
def create(self, validated_data):
raise NotImplementedError('`create()` must be implemented.')
def save(self, **kwargs):
...
... a lot of assertions and safety checks ...
...
validated_data = dict(
list(self.validated_data.items()) +
list(kwargs.items())
)
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
....
else:
self.instance = self.create(validated_data)
...
return self.instance
Okay, so, in this base class methods update
and create
are left to concrete subclasses to be implemented (as details will vary for serializers such as ListSerializer
or ModelSerializer
).
However, save
is implemented and it basically just checks if object is new or existing (if self.instance is not None
) and calls update
or create
respectively. This code will be called in every other serializer.
Let’s take a look at concrete subclass:
def create(self, validated_data):
...
... some stuff happening
...
try:
# Here is the important part! Creating new object!
instance = ModelClass.objects.create(**validated_data)
except TypeError:
raise TypeError(msg)
# Save many-to-many relationships after the instance is created.
if many_to_many:
for field_name, value in many_to_many.items():
set_many(instance, field_name, value)
return instance
def update(self, instance, validated_data):
raise_errors_on_nested_writes('update', self, validated_data)
info = model_meta.get_field_info(instance)
# Simply set each attribute on the instance, and then save it.
# Note that unlike `.create()` we don't need to treat many-to-many
# relationships as being a special case. During updates we already
# have an instance pk for the relationships to be associated with.
for attr, value in validated_data.items():
if attr in info.relations and info.relations[attr].to_many:
set_many(instance, attr, value)
else:
setattr(instance, attr, value)
instance.save()
return instance
As you can see both create
and update
call set_many(instance, attr, value)
to set values for object attributes. However, create
does one critical call before: ModelClass.objects.create(**validated_data)
. This actually creates new instance.
I hope this clears it up a bit.
10👍
In Django Rest Framework documentation they explained very clearly when to override save method and when create method.
I am posting their explanation here for your convenience
In some cases the .create() and .update() method names may not be meaningful. For example, in a contact form we may not be creating new instances, but instead sending an email or other message.
In these cases you might instead choose to override .save() directly, as being more readable and meaningful.
Example:-
class ContactForm(serializers.Serializer):
email = serializers.EmailField()
message = serializers.CharField()
def save(self):
email = self.validated_data['email']
message = self.validated_data['message']
send_email(from=email, message=message)
- [Django]-Should django model object instances be passed to celery?
- [Django]-Additional conditions on join in django
- [Django]-How do I use Django's MultiWidget?