Commit 2a1485e0 by Tom Christie

Final bits of docs for ModelSerializer fields API

parent 48d15f6f
...@@ -457,7 +457,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the ...@@ -457,7 +457,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the
name = CharField(allow_blank=True, max_length=100, required=False) name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all()) owner = PrimaryKeyRelatedField(queryset=User.objects.all())
## Specifying which fields should be included ## Specifying which fields to include
If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`.
...@@ -499,7 +499,7 @@ You can add extra fields to a `ModelSerializer` or override the default fields b ...@@ -499,7 +499,7 @@ You can add extra fields to a `ModelSerializer` or override the default fields b
Extra fields can correspond to any property or callable on the model. Extra fields can correspond to any property or callable on the model.
## Specifying which fields should be read-only ## Specifying read only fields
You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the shortcut Meta option, `read_only_fields`. You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the shortcut Meta option, `read_only_fields`.
...@@ -528,7 +528,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details ...@@ -528,7 +528,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details
--- ---
## Specifying additional keyword arguments for fields. ## Additional keyword arguments
There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer. There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer.
...@@ -567,31 +567,62 @@ The inner `Meta` class on serializers is not inherited from parent classes by de ...@@ -567,31 +567,62 @@ The inner `Meta` class on serializers is not inherited from parent classes by de
Typically we would recommend *not* using inheritance on inner Meta classes, but instead declaring all options explicitly. Typically we would recommend *not* using inheritance on inner Meta classes, but instead declaring all options explicitly.
## Advanced `ModelSerializer` usage ## Customizing field mappings
The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer. The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.
#### `.serializer_field_mapping` Normally if a `ModelSerializer` does not generate the fields you need by default the you should either add them to the class explicitly, or simply use a regular `Serializer` class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.
### `.serializer_field_mapping`
A mapping of Django model classes to REST framework serializer classes. You can override this mapping to alter the default serializer classes that should be used for each model class. A mapping of Django model classes to REST framework serializer classes. You can override this mapping to alter the default serializer classes that should be used for each model class.
#### `.serializer_relational_field` ### `.serializer_relational_field`
This property should be the serializer field class, that is used for relational fields by default. For `ModelSerializer` this defaults to `PrimaryKeyRelatedField`. For `HyperlinkedModelSerializer` this defaults to `HyperlinkedRelatedField`. This property should be the serializer field class, that is used for relational fields by default. For `ModelSerializer` this defaults to `PrimaryKeyRelatedField`. For `HyperlinkedModelSerializer` this defaults to `HyperlinkedRelatedField`.
#### The build field methods ### The field_class and field_kwargs API
The following methods are called to determine the class and keyword arguments for each field that should be automatically included on the serializer. Each of these methods should return a two tuple of `(field_class, field_kwargs)`.
### `.build_standard_field(self, field_name, model_field)`
Called to generate a serializer field that maps to a standard model field.
The default implementation returns a serializer class based on the `serializer_field_mapping` attribute.
### `.build_relational_field(self, field_name, relation_info)`
Called to generate a serializer field that maps to a relational model field.
The default implementation returns a serializer class based on the `serializer_relational_field` attribute.
The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.
### `.build_nested_field(self, field_name, relation_info, nested_depth)`
Called to generate a serializer field that maps to a relational model field, when the `depth` option has been set.
The default implementation dynamically creates a nested serializer class based on either `ModelSerializer` or `HyperlinkedModelSerializer`.
The `nested_depth` will be the value of the `depth` option, minus one.
The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.
### `.build_property_field(self, field_name, model_class)`
#### `build_standard_field(**kwargs)` Called to generate a serializer field that maps to a property or zero-argument method on the model class.
#### `build_relational_field(**kwargs)` The default implementation returns a `ReadOnlyField` class.
#### `build_nested_field(**kwargs)` ### `.build_url_field(self, field_name, model_class)`
#### `build_property_field(**kwargs)` Called to generate a serializer field for the serializer's own `url` field. The default implementation returns a `HyperlinkedIdentityField` class.
#### `build_url_field(**kwargs)` ### `.build_unknown_field(self, field_name, model_class)`
#### `build_unknown_field(**kwargs)` Called when the field name did not map to any model field or model property.
The default implementation raises an error, although subclasses may customize this behavior.
--- ---
......
...@@ -239,6 +239,10 @@ body a:hover{ ...@@ -239,6 +239,10 @@ body a:hover{
} }
} }
h1 code, h2 code, h3 code, h4 code, h5 code {
color: #333;
}
/* sticky footer and footer */ /* sticky footer and footer */
html, body { html, body {
height: 100%; height: 100%;
......
...@@ -24,7 +24,7 @@ FieldInfo = namedtuple('FieldResult', [ ...@@ -24,7 +24,7 @@ FieldInfo = namedtuple('FieldResult', [
RelationInfo = namedtuple('RelationInfo', [ RelationInfo = namedtuple('RelationInfo', [
'model_field', 'model_field',
'related', 'related_model',
'to_many', 'to_many',
'has_through_model' 'has_through_model'
]) ])
...@@ -77,7 +77,7 @@ def get_field_info(model): ...@@ -77,7 +77,7 @@ def get_field_info(model):
for field in [field for field in opts.fields if field.serialize and field.rel]: for field in [field for field in opts.fields if field.serialize and field.rel]:
forward_relations[field.name] = RelationInfo( forward_relations[field.name] = RelationInfo(
model_field=field, model_field=field,
related=_resolve_model(field.rel.to), related_model=_resolve_model(field.rel.to),
to_many=False, to_many=False,
has_through_model=False has_through_model=False
) )
...@@ -86,7 +86,7 @@ def get_field_info(model): ...@@ -86,7 +86,7 @@ def get_field_info(model):
for field in [field for field in opts.many_to_many if field.serialize]: for field in [field for field in opts.many_to_many if field.serialize]:
forward_relations[field.name] = RelationInfo( forward_relations[field.name] = RelationInfo(
model_field=field, model_field=field,
related=_resolve_model(field.rel.to), related_model=_resolve_model(field.rel.to),
to_many=True, to_many=True,
has_through_model=( has_through_model=(
not field.rel.through._meta.auto_created not field.rel.through._meta.auto_created
...@@ -99,7 +99,7 @@ def get_field_info(model): ...@@ -99,7 +99,7 @@ def get_field_info(model):
accessor_name = relation.get_accessor_name() accessor_name = relation.get_accessor_name()
reverse_relations[accessor_name] = RelationInfo( reverse_relations[accessor_name] = RelationInfo(
model_field=None, model_field=None,
related=relation.model, related_model=relation.model,
to_many=relation.field.rel.multiple, to_many=relation.field.rel.multiple,
has_through_model=False has_through_model=False
) )
...@@ -109,7 +109,7 @@ def get_field_info(model): ...@@ -109,7 +109,7 @@ def get_field_info(model):
accessor_name = relation.get_accessor_name() accessor_name = relation.get_accessor_name()
reverse_relations[accessor_name] = RelationInfo( reverse_relations[accessor_name] = RelationInfo(
model_field=None, model_field=None,
related=relation.model, related_model=relation.model,
to_many=True, to_many=True,
has_through_model=( has_through_model=(
(getattr(relation.field.rel, 'through', None) is not None) (getattr(relation.field.rel, 'through', None) is not None)
......
...@@ -206,7 +206,7 @@ class TestRegularFieldMappings(TestCase): ...@@ -206,7 +206,7 @@ class TestRegularFieldMappings(TestCase):
with self.assertRaises(ImproperlyConfigured) as excinfo: with self.assertRaises(ImproperlyConfigured) as excinfo:
TestSerializer().fields TestSerializer().fields
expected = 'Field name `invalid` is not valid for model `ModelBase`.' expected = 'Field name `invalid` is not valid for model `RegularFieldsModel`.'
assert str(excinfo.exception) == expected assert str(excinfo.exception) == expected
def test_missing_field(self): def test_missing_field(self):
......
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