mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-09 08:00:52 +03:00
nested -> depth
This commit is contained in:
parent
6e4ab09aae
commit
351382fe35
|
@ -107,21 +107,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.
|
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):
|
class UserSerializer(serializers.Serializer):
|
||||||
email = serializers.EmailField()
|
email = serializers.Field()
|
||||||
username = serializers.CharField()
|
username = serializers.Field()
|
||||||
|
|
||||||
def restore_object(self, attrs, instance=None):
|
|
||||||
return User(**attrs)
|
|
||||||
|
|
||||||
|
|
||||||
class CommentSerializer(serializers.Serializer):
|
class CommentSerializer(serializers.Serializer):
|
||||||
user = UserSerializer()
|
user = UserSerializer()
|
||||||
title = serializers.CharField()
|
title = serializers.Field()
|
||||||
content = serializers.CharField(max_length=200)
|
content = serializers.Field()
|
||||||
created = serializers.DateTimeField()
|
created = serializers.Field()
|
||||||
|
|
||||||
def restore_object(self, attrs, instance=None):
|
---
|
||||||
return Comment(**attrs)
|
|
||||||
|
**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
|
## Creating custom fields
|
||||||
|
|
||||||
|
@ -225,40 +225,54 @@ For example:
|
||||||
|
|
||||||
## Specifiying nested serialization
|
## 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 AccountSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
exclude = ('id',)
|
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):
|
**Signature**: `.get_pk_field(self, model_field)`
|
||||||
class Meta:
|
|
||||||
model = Account
|
|
||||||
|
|
||||||
|
Returns the field instance that should be used to represent the pk field.
|
||||||
|
|
||||||
|
### get_nested_field
|
||||||
|
|
||||||
|
**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):
|
def get_pk_field(self, model_field):
|
||||||
return serializers.Field(read_only=True)
|
return None
|
||||||
|
|
||||||
def get_nested_field(self, model_field):
|
|
||||||
return serializers.ModelSerializer()
|
|
||||||
|
|
||||||
def get_related_field(self, model_field, to_many=False):
|
|
||||||
queryset = model_field.rel.to._default_manager
|
|
||||||
if to_many:
|
|
||||||
return serializers.ManyRelatedField(queryset=queryset)
|
|
||||||
return serializers.RelatedField(queryset=queryset)
|
|
||||||
|
|
||||||
def get_field(self, model_field):
|
|
||||||
return serializers.ModelField(model_field=model_field)
|
|
||||||
|
|
||||||
|
|
||||||
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
|
||||||
|
|
|
@ -74,7 +74,7 @@ class SerializerOptions(object):
|
||||||
Meta class options for Serializer
|
Meta class options for Serializer
|
||||||
"""
|
"""
|
||||||
def __init__(self, meta):
|
def __init__(self, meta):
|
||||||
self.nested = getattr(meta, 'nested', False)
|
self.depth = getattr(meta, 'depth', 0)
|
||||||
self.fields = getattr(meta, 'fields', ())
|
self.fields = getattr(meta, 'fields', ())
|
||||||
self.exclude = getattr(meta, 'exclude', ())
|
self.exclude = getattr(meta, 'exclude', ())
|
||||||
|
|
||||||
|
@ -156,10 +156,8 @@ class BaseSerializer(Field):
|
||||||
"""
|
"""
|
||||||
super(BaseSerializer, self).initialize(parent)
|
super(BaseSerializer, self).initialize(parent)
|
||||||
self.stack = parent.stack[:]
|
self.stack = parent.stack[:]
|
||||||
if parent.opts.nested and not isinstance(parent.opts.nested, bool):
|
if parent.opts.depth:
|
||||||
self.opts.nested = parent.opts.nested - 1
|
self.opts.depth = parent.opts.depth - 1
|
||||||
else:
|
|
||||||
self.opts.nested = parent.opts.nested
|
|
||||||
|
|
||||||
#####
|
#####
|
||||||
# Methods to convert or revert from objects <--> primative representations.
|
# Methods to convert or revert from objects <--> primative representations.
|
||||||
|
@ -182,14 +180,10 @@ class BaseSerializer(Field):
|
||||||
ret = self._dict_class()
|
ret = self._dict_class()
|
||||||
ret.fields = {}
|
ret.fields = {}
|
||||||
|
|
||||||
fields = self.get_fields(serialize=True, obj=obj, nested=self.opts.nested)
|
fields = self.get_fields(serialize=True, obj=obj, nested=bool(self.opts.depth))
|
||||||
for field_name, field in fields.items():
|
for field_name, field in fields.items():
|
||||||
key = self.get_field_key(field_name)
|
key = self.get_field_key(field_name)
|
||||||
try:
|
value = field.field_to_native(obj, field_name)
|
||||||
value = field.field_to_native(obj, field_name)
|
|
||||||
except RecursionOccured:
|
|
||||||
field = self.get_fields(serialize=True, obj=obj, nested=False)[field_name]
|
|
||||||
value = field.field_to_native(obj, field_name)
|
|
||||||
ret[key] = value
|
ret[key] = value
|
||||||
ret.fields[key] = field
|
ret.fields[key] = field
|
||||||
return ret
|
return ret
|
||||||
|
@ -199,7 +193,7 @@ class BaseSerializer(Field):
|
||||||
Core of deserialization, together with `restore_object`.
|
Core of deserialization, together with `restore_object`.
|
||||||
Converts a dictionary of data into a dictionary of deserialized fields.
|
Converts a dictionary of data into a dictionary of deserialized fields.
|
||||||
"""
|
"""
|
||||||
fields = self.get_fields(serialize=False, data=data, nested=self.opts.nested)
|
fields = self.get_fields(serialize=False, data=data, nested=bool(self.opts.depth))
|
||||||
reverted_data = {}
|
reverted_data = {}
|
||||||
for field_name, field in fields.items():
|
for field_name, field in fields.items():
|
||||||
try:
|
try:
|
||||||
|
@ -213,7 +207,8 @@ class BaseSerializer(Field):
|
||||||
"""
|
"""
|
||||||
Run `validate_<fieldname>()` and `validate()` methods on the serializer
|
Run `validate_<fieldname>()` and `validate()` methods on the serializer
|
||||||
"""
|
"""
|
||||||
fields = self.get_fields(serialize=False, data=attrs, nested=self.opts.nested)
|
# TODO: refactor this so we're not determining the fields again
|
||||||
|
fields = self.get_fields(serialize=False, data=attrs, nested=bool(self.opts.depth))
|
||||||
|
|
||||||
for field_name, field in fields.items():
|
for field_name, field in fields.items():
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user