This field can be applied to any "to-one" relationship, such as a `ForeignKey` field.
`PrimaryKeyRelatedField` and `ManyPrimaryKeyRelatedField` will represent the target of the relationship using it's primary key.
`PrimaryKeyRelatedField` will represent the target of the field using it's primary key.
By default these fields are read-write, although you can change this behaviour using the `read_only` flag.
Be default, `PrimaryKeyRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
**Arguments**:
## ManyPrimaryKeyRelatedField
*`queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
This field can be applied to any "to-many" relationship, such as a `ManyToManyField` field, or a reverse `ForeignKey` relationship.
## SlugRelatedField / ManySlugRelatedField
`PrimaryKeyRelatedField` will represent the targets of the field using their primary key.
`SlugRelatedField` and `ManySlugRelatedField` will represent the target of the relationship using a unique slug.
Be default, `ManyPrimaryKeyRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
By default these fields read-write, although you can change this behaviour using the `read_only` flag.
## HyperlinkedRelatedField
**Arguments**:
This field can be applied to any "to-one" relationship, such as a `ForeignKey` field.
*`slug_field` - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, `username`.
*`queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
`HyperlinkedRelatedField` will represent the target of the field using a hyperlink. You must include a named URL pattern in your URL conf, with a name like `'{model-name}-detail'` that corresponds to the target of the hyperlink.
Be default, `HyperlinkedRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
`HyperlinkedRelatedField` and `ManyHyperlinkedRelatedField` will represent the target of the relationship using a hyperlink.
## ManyHyperlinkedRelatedField
By default, `HyperlinkedRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
This field can be applied to any "to-many" relationship, such as a `ManyToManyField` field, or a reverse `ForeignKey` relationship.
**Arguments**:
`ManyHyperlinkedRelatedField` will represent the targets of the field using hyperlinks. You must include a named URL pattern in your URL conf, with a name like `'{model-name}-detail'` that corresponds to the target of the hyperlink.
*`view_name` - The view name that should be used as the target of the relationship. **required**.
*`format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
Be default, `ManyHyperlinkedRelatedField` is read-write, although you can change this behaviour using the `read_only` flag.
*`queryset` - By default `ModelSerializer` classes will use the default queryset for the relationship. `Serializer` classes must either set a queryset explicitly, or set `read_only=True`.
*`slug_field` - The field on the target that should be used for the lookup. Default is `'slug'`.
*`slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
## HyperLinkedIdentityField
## HyperLinkedIdentityField
This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer.
This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer.
You must include a named URL pattern in your URL conf, with a name like `'{model-name}-detail'` that corresponds to the model.
This field is always read-only.
This field is always read-only.
**Arguments**:
*`view_name` - The view name that should be used as the target of the relationship. **required**.
*`format` - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the `format` argument.
@@ -47,7 +47,7 @@ The first part of serializer class defines the fields that get serialized/deseri
...
@@ -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.
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.
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.
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.
### Field-level validation
### 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:
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
from rest_framework import serializers
...
@@ -88,16 +97,22 @@ You can specify custom field-level validation by adding `validate_<fieldname>()`
...
@@ -88,16 +97,22 @@ You can specify custom field-level validation by adding `validate_<fieldname>()`
def validate_title(self, attrs, source):
def validate_title(self, attrs, source):
"""
"""
Check that the blog post is about Django
Check that the blog post is about Django.
"""
"""
value = attrs[source]
value = attrs[source]
if "Django" not in value:
if "django" not in value.lower():
raise serializers.ValidationError("Blog post is not about Django")
raise serializers.ValidationError("Blog post is not about Django")
return attrs
return attrs
### Final cross-field validation
### 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.
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`.
The generic views provided by REST framework call the `.save()` method when updating or creating entities.
@@ -92,7 +92,7 @@ Let's take a look at how we can compose our views by using the mixin classes.
...
@@ -92,7 +92,7 @@ Let's take a look at how we can compose our views by using the mixin classes.
class SnippetList(mixins.ListModelMixin,
class SnippetList(mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.CreateModelMixin,
generics.MultipleObjectBaseView):
generics.MultipleObjectAPIView):
model = Snippet
model = Snippet
serializer_class = SnippetSerializer
serializer_class = SnippetSerializer
...
@@ -102,7 +102,7 @@ Let's take a look at how we can compose our views by using the mixin classes.
...
@@ -102,7 +102,7 @@ Let's take a look at how we can compose our views by using the mixin classes.
def post(self, request, *args, **kwargs):
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
return self.create(request, *args, **kwargs)
We'll take a moment to examine exactly what's happening here - We're building our view using `MultipleObjectBaseView`, and adding in `ListModelMixin` and `CreateModelMixin`.
We'll take a moment to examine exactly what's happening here - We're building our view using `MultipleObjectAPIView`, and adding in `ListModelMixin` and `CreateModelMixin`.
The base class provides the core functionality, and the mixin classes provide the `.list()` and `.create()` actions. We're then explicitly binding the `get` and `post` methods to the appropriate actions. Simple enough stuff so far.
The base class provides the core functionality, and the mixin classes provide the `.list()` and `.create()` actions. We're then explicitly binding the `get` and `post` methods to the appropriate actions. Simple enough stuff so far.
@@ -19,12 +19,19 @@ First up we're going to define some serializers in `quickstart/serializers.py` t
...
@@ -19,12 +19,19 @@ First up we're going to define some serializers in `quickstart/serializers.py` t
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class GroupSerializer(serializers.HyperlinkedModelSerializer):
permissions = serializers.ManySlugRelatedField(
slug_field='codename',
queryset=Permission.objects.all()
)
class Meta:
class Meta:
model = Group
model = Group
fields = ('url', 'name', 'permissions')
fields = ('url', 'name', 'permissions')
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
Notice that we're using hyperlinked relations in this case, with `HyperlinkedModelSerializer`. You can also use primary key and various other relationships, but hyperlinking is good RESTful design.
We've also overridden the `permission` field on the `GroupSerializer`. In this case we don't want to use a hyperlinked representation, but instead use the list of permission codenames associated with the group, so we've used a `ManySlugRelatedField`, using the `codename` field for the representation.
## Views
## Views
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
Right, we'd better write some views then. Open `quickstart/views.py` and get typing.
...
@@ -152,7 +159,7 @@ We can now access our API, both from the command-line, using tools like `curl`..
...
@@ -152,7 +159,7 @@ We can now access our API, both from the command-line, using tools like `curl`..