aboutsummaryrefslogtreecommitdiffstats
path: root/docs/api-guide/serializers.md
diff options
context:
space:
mode:
authorTom Christie2012-11-09 13:49:52 +0000
committerTom Christie2012-11-09 13:49:52 +0000
commit8953a60196cb55ec75902882314da5a42636349c (patch)
tree43bf6ea1f69955aeecd83fb9f866d92ea9a5f3df /docs/api-guide/serializers.md
parentb78872b7dbb55f1aa2d21f15fbb952f0c7156326 (diff)
parent9aaeeacdfebc244850e82469e4af45af252cca4d (diff)
downloaddjango-rest-framework-8953a60196cb55ec75902882314da5a42636349c.tar.bz2
Merge with master
Diffstat (limited to 'docs/api-guide/serializers.md')
-rw-r--r--docs/api-guide/serializers.md128
1 files changed, 88 insertions, 40 deletions
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index 47958fe3..0cdae1ce 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -47,7 +47,7 @@ The first part of serializer class defines the fields that get serialized/deseri
We can now use `CommentSerializer` to serialize a comment, or list of comments. Again, using the `Serializer` class looks a lot like using a `Form` class.
- serializer = CommentSerializer(instance=comment)
+ serializer = CommentSerializer(comment)
serializer.data
# {'email': u'leila@example.com', 'content': u'foo bar', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
@@ -65,18 +65,54 @@ Deserialization is similar. First we parse a stream into python native datatype
...then we restore those native datatypes into a fully populated object instance.
- serializer = CommentSerializer(data)
+ serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.object
# <Comment object at 0x10633b2d0>
>>> serializer.deserialize('json', stream)
+When deserializing data, we can either create a new instance, or update an existing instance.
+
+ serializer = CommentSerializer(data=data) # Create new instance
+ serializer = CommentSerializer(comment, data=data) # Update `instance`
+
## Validation
When deserializing data, you always need to call `is_valid()` before attempting to access the deserialized object. If any validation errors occur, the `.errors` and `.non_field_errors` properties will contain the resulting error messages.
-**TODO: Describe validation in more depth**
+### Field-level validation
+
+You can specify custom field-level validation by adding `.validate_<fieldname>` methods to your `Serializer` subclass. These are analagous to `.clean_<fieldname>` methods on Django forms, but accept slightly different arguments.
+
+They take a dictionary of deserialized attributes as a first argument, and the field name in that dictionary as a second argument (which will be either the name of the field or the value of the `source` argument to the field, if one was provided).
+
+Your `validate_<fieldname>` methods should either just return the `attrs` dictionary or raise a `ValidationError`. For example:
+
+ from rest_framework import serializers
+
+ class BlogPostSerializer(serializers.Serializer):
+ title = serializers.CharField(max_length=100)
+ content = serializers.CharField()
+
+ def validate_title(self, attrs, source):
+ """
+ Check that the blog post is about Django.
+ """
+ value = attrs[source]
+ if "django" not in value.lower():
+ raise serializers.ValidationError("Blog post is not about Django")
+ return attrs
+
+### Object-level validation
+
+To do any other validation that requires access to multiple fields, add a method called `.validate()` to your `Serializer` subclass. This method takes a single argument, which is the `attrs` dictionary. It should raise a `ValidationError` if necessary, or just return `attrs`.
+
+## Saving object state
+
+Serializers also include a `.save()` method that you can override if you want to provide a method of persisting the state of a deserialized object. The default behavior of the method is to simply call `.save()` on the deserialized object instance.
+
+The generic views provided by REST framework call the `.save()` method when updating or creating entities.
## Dealing with nested objects
@@ -86,21 +122,21 @@ where some of the attributes of an object might not be simple datatypes such as
The `Serializer` class is itself a type of `Field`, and can be used to represent relationships where one object type is nested inside another.
class UserSerializer(serializers.Serializer):
- email = serializers.EmailField()
- username = serializers.CharField()
-
- def restore_object(self, attrs, instance=None):
- return User(**attrs)
-
+ email = serializers.Field()
+ username = serializers.Field()
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
- title = serializers.CharField()
- content = serializers.CharField(max_length=200)
- created = serializers.DateTimeField()
-
- def restore_object(self, attrs, instance=None):
- return Comment(**attrs)
+ title = serializers.Field()
+ content = serializers.Field()
+ created = serializers.Field()
+
+---
+
+**Note**: Nested serializers are only suitable for read-only representations, as there are cases where they would have ambiguous or non-obvious behavior if used when updating instances. For read-write representations you should always use a flat representation, by using one of the `RelatedField` subclasses.
+
+---
+
## Creating custom fields
@@ -114,7 +150,6 @@ Let's look at an example of serializing a class that represents an RGB color val
"""
A color represented in the RGB colorspace.
"""
-
def __init__(self, red, green, blue):
assert(red >= 0 and green >= 0 and blue >= 0)
assert(red < 256 and green < 256 and blue < 256)
@@ -124,7 +159,6 @@ Let's look at an example of serializing a class that represents an RGB color val
"""
Color objects are serialized into "rgb(#, #, #)" notation.
"""
-
def to_native(self, obj):
return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue)
@@ -156,7 +190,7 @@ As an example, let's create a field that can be used represent the class name of
# ModelSerializers
Often you'll want serializer classes that map closely to model definitions.
-The `ModelSerializer` class lets you automatically create a Serializer class with fields that corrospond to the Model fields.
+The `ModelSerializer` class lets you automatically create a Serializer class with fields that correspond to the Model fields.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
@@ -169,13 +203,13 @@ The `ModelSerializer` class lets you automatically create a Serializer class wit
You can add extra fields to a `ModelSerializer` or override the default fields by declaring fields on the class, just as you would for a `Serializer` class.
class AccountSerializer(serializers.ModelSerializer):
- url = CharField(source='get_absolute_url', readonly=True)
+ url = CharField(source='get_absolute_url', read_only=True)
group = NaturalKeyField()
class Meta:
model = Account
-Extra fields can corrospond to any property or callable on the model.
+Extra fields can correspond to any property or callable on the model.
## Relational fields
@@ -187,7 +221,7 @@ The `PrimaryKeyRelatedField` and `HyperlinkedRelatedField` fields provide altern
The `ModelSerializer` class can itself be used as a field, in order to serialize relationships using nested representations.
-The `RelatedField` class may be subclassed to create a custom represenation of a relationship. The subclass should override `.to_native()`, and optionally `.from_native()` if deserialization is supported.
+The `RelatedField` class may be subclassed to create a custom representation of a relationship. The subclass should override `.to_native()`, and optionally `.from_native()` if deserialization is supported.
All the relational fields may be used for any relationship or reverse relationship on a model.
@@ -204,40 +238,54 @@ For example:
## Specifiying nested serialization
-The default `ModelSerializer` uses primary keys for relationships, but you can also easily generate nested representations using the `nested` option:
+The default `ModelSerializer` uses primary keys for relationships, but you can also easily generate nested representations using the `depth` option:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ('id',)
- nested = True
+ depth = 1
-The `nested` option may be set to either `True`, `False`, or an integer value. If given an integer value it indicates the depth of relationships that should be traversed before reverting to a flat representation.
+The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
-When serializing objects using a nested representation any occurances of recursion will be recognised, and will fall back to using a flat representation.
+## Customising the default fields
-## Customising the default fields used by a ModelSerializer
+You can create customized subclasses of `ModelSerializer` that use a different set of default fields for the representation, by overriding various `get_<field_type>_field` methods.
+Each of these methods may either return a field or serializer instance, or `None`.
+### get_pk_field
- class AccountSerializer(serializers.ModelSerializer):
- class Meta:
- model = Account
+**Signature**: `.get_pk_field(self, model_field)`
- def get_pk_field(self, model_field):
- return serializers.Field(readonly=True)
+Returns the field instance that should be used to represent the pk field.
- def get_nested_field(self, model_field):
- return serializers.ModelSerializer()
+### get_nested_field
- def get_related_field(self, model_field, to_many=False):
- queryset = model_field.rel.to._default_manager
- if to_many:
- return return serializers.ManyRelatedField(queryset=queryset)
- return serializers.RelatedField(queryset=queryset)
+**Signature**: `.get_nested_field(self, model_field)`
+
+Returns the field instance that should be used to represent a related field when `depth` is specified as being non-zero.
+
+### get_related_field
+
+**Signature**: `.get_related_field(self, model_field, to_many=False)`
+
+Returns the field instance that should be used to represent a related field when `depth` is not specified, or when nested representations are being used and the depth reaches zero.
+
+### get_field
+
+**Signature**: `.get_field(self, model_field)`
+
+Returns the field instance that should be used for non-relational, non-pk fields.
+
+### Example:
+
+The following custom model serializer could be used as a base class for model serializers that should always exclude the pk by default.
+
+ class NoPKModelSerializer(serializers.ModelSerializer):
+ def get_pk_field(self, model_field):
+ return None
- def get_field(self, model_field):
- return serializers.ModelField(model_field=model_field)
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion