Tweak pre/post save hooks. Return instance in .update().

This commit is contained in:
Tom Christie 2014-10-08 12:17:30 +01:00
parent af0f01c5b6
commit 0cbb57b40f
3 changed files with 40 additions and 23 deletions

View File

@ -116,11 +116,12 @@ This would now be split out into two separate methods.
instance.language = validated_data.get('language', instance.language) instance.language = validated_data.get('language', instance.language)
instance.style = validated_data.get('style', instance.style) instance.style = validated_data.get('style', instance.style)
instance.save() instance.save()
return instance
def create(self, validated_data): def create(self, validated_data):
return Snippet.objects.create(**validated_data) return Snippet.objects.create(**validated_data)
Note that the `.create` method should return the newly created object instance. Note that these methods should return the newly created object instance.
#### Use `.validated_data` instead of `.object`. #### Use `.validated_data` instead of `.object`.
@ -592,18 +593,27 @@ The `UniqueTogetherValidator` should be applied to a serializer, and takes a `qu
The view logic for the default method handlers has been significantly simplified, due to the new serializers API. The view logic for the default method handlers has been significantly simplified, due to the new serializers API.
#### Removal of pre/post save hooks. #### Changes to pre/post save hooks.
The following method hooks no longer exist on the new, simplified, generic views: `pre_save`, `post_save`, `pre_delete`, `post_delete`. The `pre_save` and `post_save` hooks no longer exist, but are replaced with `perform_create(self, serializer)` and `perform_update(self, serializer)`.
If you do need custom behavior, you might choose to instead override the `.save()` method on your serializer class. For example: These method should save the object instance by calling `serializer.save()`, adding in any explicit additional arguments as required. They may also perform any custom pre-save or post-save behavior.
def save(self, *args, **kwargs): For example:
instance = super(MySerializer).save(*args, **kwarg)
def perform_create(self, serializer):
# Include the owner attribute directly, rather than from request data.
instance = serializer.save(owner=self.request.user)
# Perform a custom post-save action.
send_email(instance.to_email, instance.message) send_email(instance.to_email, instance.message)
return instance
Alternatively write your view logic exlpicitly, or tie your pre/post save behavior into the model class or model manager. The `pre_delete` and `post_delete` hooks no longer exist, and are replaced with `.perform_destroy(self, instance)`, which should delete the instance and perform any custom actions.
def perform_destroy(self, instance):
# Perform a custom pre-delete action.
send_deletion_alert(user=instance.created_by, deleted=instance)
# Delete the object instance.
instance.delete()
#### Removal of view attributes. #### Removal of view attributes.

View File

@ -20,11 +20,11 @@ class CreateModelMixin(object):
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
self.create_valid(serializer) self.perform_create(serializer)
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def create_valid(self, serializer): def perform_create(self, serializer):
serializer.save() serializer.save()
def get_success_headers(self, data): def get_success_headers(self, data):
@ -67,10 +67,10 @@ class UpdateModelMixin(object):
instance = self.get_object() instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
self.update_valid(serializer) self.preform_update(serializer)
return Response(serializer.data) return Response(serializer.data)
def update_valid(self, serializer): def preform_update(self, serializer):
serializer.save() serializer.save()
def partial_update(self, request, *args, **kwargs): def partial_update(self, request, *args, **kwargs):
@ -84,9 +84,12 @@ class DestroyModelMixin(object):
""" """
def destroy(self, request, *args, **kwargs): def destroy(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()
instance.delete() self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
# The AllowPUTAsCreateMixin was previously the default behaviour # The AllowPUTAsCreateMixin was previously the default behaviour
# for PUT requests. This has now been removed and must be *explicitly* # for PUT requests. This has now been removed and must be *explicitly*

View File

@ -83,7 +83,10 @@ class BaseSerializer(Field):
) )
if self.instance is not None: if self.instance is not None:
self.update(self.instance, validated_data) self.instance = self.update(self.instance, validated_data)
assert self.instance is not None, (
'`update()` did not return an object instance.'
)
else: else:
self.instance = self.create(validated_data) self.instance = self.create(validated_data)
assert self.instance is not None, ( assert self.instance is not None, (
@ -444,19 +447,19 @@ class ModelSerializer(Serializer):
self.validators.extend(validators) self.validators.extend(validators)
self._kwargs['validators'] = validators self._kwargs['validators'] = validators
def create(self, attrs): def create(self, validated_attrs):
ModelClass = self.Meta.model ModelClass = self.Meta.model
# Remove many-to-many relationships from attrs. # Remove many-to-many relationships from validated_attrs.
# They are not valid arguments to the default `.create()` method, # They are not valid arguments to the default `.create()` method,
# as they require that the instance has already been saved. # as they require that the instance has already been saved.
info = model_meta.get_field_info(ModelClass) info = model_meta.get_field_info(ModelClass)
many_to_many = {} many_to_many = {}
for field_name, relation_info in info.relations.items(): for field_name, relation_info in info.relations.items():
if relation_info.to_many and (field_name in attrs): if relation_info.to_many and (field_name in validated_attrs):
many_to_many[field_name] = attrs.pop(field_name) many_to_many[field_name] = validated_attrs.pop(field_name)
instance = ModelClass.objects.create(**attrs) instance = ModelClass.objects.create(**validated_attrs)
# Save many-to-many relationships after the instance is created. # Save many-to-many relationships after the instance is created.
if many_to_many: if many_to_many:
@ -465,10 +468,11 @@ class ModelSerializer(Serializer):
return instance return instance
def update(self, obj, attrs): def update(self, instance, validated_attrs):
for attr, value in attrs.items(): for attr, value in validated_attrs.items():
setattr(obj, attr, value) setattr(instance, attr, value)
obj.save() instance.save()
return instance
def get_unique_together_validators(self): def get_unique_together_validators(self):
field_names = set([ field_names = set([