Commit 0cbb57b4 by Tom Christie

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

parent af0f01c5
...@@ -116,11 +116,12 @@ This would now be split out into two separate methods. ...@@ -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 ...@@ -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.
......
...@@ -20,11 +20,11 @@ class CreateModelMixin(object): ...@@ -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): ...@@ -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): ...@@ -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*
......
...@@ -83,7 +83,10 @@ class BaseSerializer(Field): ...@@ -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): ...@@ -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): ...@@ -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([
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment