From babdc78e61ac915fa4a01bdfb04e11a32dbf5d79 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Thu, 9 Oct 2014 11:39:01 +0100
Subject: Typo
---
docs/api-guide/validators.md | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 docs/api-guide/validators.md
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
new file mode 100644
index 00000000..e69de29b
--
cgit v1.2.3
From 27622058872c00e357deb7d7e86619a793ef4b41 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Fri, 31 Oct 2014 13:47:36 +0000
Subject: Validator documentation and tweaks
---
docs/api-guide/validators.md | 183 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 183 insertions(+)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index e69de29b..52c9e082 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -0,0 +1,183 @@
+
+
+# Validators
+
+> Validators can be useful for re-using validation logic between different types of fields.
+>
+> — [Django documentation][cite]
+
+Most of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes.
+
+Sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.
+
+## Validation in REST framework
+
+Validation in Django REST framework serializers is handled a little differently to how validation works in Django's `ModelForm` class.
+
+With `ModelForm` the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:
+
+* It introduces a proper separation of concerns, making your code behaviour more obvious.
+* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behaviour being used for `ModelSerializer` is simple to replicate.
+* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behaviour being called on the model instance.
+
+When you're using `ModelSerializer` all of this is handled automatically for you. If you want to drop down to using a `Serializer` classes instead, then you need to define the validation rules explicitly.
+
+#### Example
+
+As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.
+
+ class CustomerReportRecord(models.Model):
+ time_raised = models.DateTimeField(default=timezone.now, editable=False)
+ reference = models.CharField(unique=True, max_length=20)
+ description = models.TextField()
+
+Here's a basic `ModelSerializer` that we can use for creating or updating instances of `CustomerReportRecord`:
+
+ class CustomerReportSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = CustomerReportRecord
+
+If we open up the Django shell using `manage.py shell` we can now
+
+ >>> from project.example.serializers import CustomerReportSerializer
+ >>> serializer = CustomerReportSerializer()
+ >>> print(repr(serializer))
+ CustomerReportSerializer():
+ id = IntegerField(label='ID', read_only=True)
+ time_raised = DateTimeField(read_only=True)
+ reference = CharField(max_length=20, validators=[])
+ description = CharField(style={'type': 'textarea'})
+
+The interesting bit here is the `reference` field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field.
+
+Because of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below.
+
+---
+
+## UniqueValidator
+
+This validator can be used to enforce the `unique=True` constraint on model fields.
+It takes a single required argument, and an optional `messages` argument:
+
+* `queryset` *required* - This is the queryset against which uniqueness should be enforced.
+* `message` - The error message that should be used when validation fails.
+
+This validator should be applied to *serializer fields*, like so:
+
+ slug = SlugField(
+ max_length=100,
+ validators=[UniqueValidator(queryset=BlogPost.objects.all())]
+ )
+
+## UniqueTogetherValidator
+
+This validator can be used to enforce `unique_together` constraints on model instances.
+It has two required arguments, and a single optional `messages` argument:
+
+* `queryset` *required* - This is the queryset against which uniqueness should be enforced.
+* `fields` *required* - A list or tuple of field names which should make a unique set. These must exist as fields on the serializer class.
+* `message` - The error message that should be used when validation fails.
+
+The validator should be applied to *serializer classes*, like so:
+
+ class ExampleSerializer(serializers.Serializer):
+ # ...
+ class Meta:
+ # ToDo items belong to a parent list, and have an ordering defined
+ # by the 'position' field. No two items in a given list may share
+ # the same position.
+ validators = [
+ UniqueTogetherValidator(
+ queryset=ToDoItem.objects.all(),
+ fields=('list', 'position')
+ )
+ ]
+
+## UniqueForDateValidator
+
+## UniqueForMonthValidator
+
+## UniqueForYearValidator
+
+These validators can be used to enforce the `unique_for_date`, `unique_for_month` and `unique_for_year` constraints on model instances. They take the following arguments:
+
+* `queryset` *required* - This is the queryset against which uniqueness should be enforced.
+* `field` *required* - A field name against which uniqueness in the given date range will be validated. This must exist as a field on the serializer class.
+* `date_field` *required* - A field name which will be used to determine date range for the uniqueness constrain. This must exist as a field on the serializer class.
+* `message` - The error message that should be used when validation fails.
+
+The validator should be applied to *serializer classes*, like so:
+
+ class ExampleSerializer(serializers.Serializer):
+ # ...
+ class Meta:
+ # Blog posts should have a slug that is unique for the current year.
+ validators = [
+ UniqueForYearValidator(
+ queryset=BlogPostItem.objects.all(),
+ field='slug',
+ date_field='published'
+ )
+ ]
+
+The date field that is used for the validation is always required to be present on the serializer class. You can't simply rely on a model class `default=...`, because the value being used for the default wouldn't be generated until after the validation has run.
+
+There are a couple of styles you may want to use for this depending on how you want your API to behave. If you're using `ModelSerializer` you'll probably simply rely on the defaults that REST framework generates for you, but if you are using `Serializer` or simply want more explicit control, use on of the styles demonstrated below.
+
+#### Using with a writable date field.
+
+If you want the date field to be writable the only thing worth noting is that you should ensure that it is always available in the input data, either by setting a `default` argument, or by setting `required=True`.
+
+ published = serializers.DateTimeField(required=True)
+
+#### Using with a read-only date field.
+
+If you want the date field to be visible, but not editable by the user, then set `read_only=True` and additionally set a `default=...` argument.
+
+ published = serializers.DateTimeField(read_only=True, default=timezone.now)
+
+The field will not be writable to the user, but the default value will still be passed through to the `validated_data`.
+
+#### Using with a hidden date field.
+
+If you want the date field to be entirely hidden from the user, then use `HiddenField`. This field type does not accept user input, but instead always returns it's default value to the `validated_data` in the serializer.
+
+ published = serializers.HiddenField(default=timezone.now)
+
+---
+
+# Writing custom validators
+
+You can use any of Django's existing validators, or write your own custom validators.
+
+## Function based
+
+A validator may be any callable that raises a `serializers.ValidationError` on failure.
+
+ def even_number(value):
+ if value % 2 != 0:
+ raise serializers.ValidationError('This field must be an even number.')
+
+## Class based
+
+To write a class based validator, use the `__call__` method. Class based validators are useful as they allow you to parameterize and reuse behavior.
+
+ class MultipleOf:
+ def __init__(self, base):
+ self.base = base
+
+ def __call__(self, value):
+ if value % self.base != 0
+ message = 'This field must be a multiple of %d.' % self.base
+ raise serializers.ValidationError(message)
+
+#### Using `set_context()`
+
+In some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a `set_context` method on a class based validator.
+
+ def set_context(self, serializer_field):
+ # Determine if this is an update or a create operation.
+ # In `__call__` we can then use that information to modify the validation behavior.
+ self.is_update = serializer_field.parent.instance is not None
+
+[cite]: https://docs.djangoproject.com/en/dev/ref/validators/
--
cgit v1.2.3
From 254701230d85612cf0210d4549c2d74f410a181d Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Fri, 31 Oct 2014 13:58:40 +0000
Subject: Fix up validators docs
---
docs/api-guide/validators.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index 52c9e082..6a0ef4ff 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -8,7 +8,7 @@
Most of the time you're dealing with validation in REST framework you'll simply be relying on the default field validation, or writing explicit validation methods on serializer or field classes.
-Sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.
+However, sometimes you'll want to place your validation logic into reusable components, so that it can easily be reused throughout your codebase. This can be achieved by using validator functions and validator classes.
## Validation in REST framework
--
cgit v1.2.3
From f387cd89da55ef88fcac504f5795ea9b591f3fba Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 10 Nov 2014 12:21:27 +0000
Subject: Uniqueness constraints imply a forced 'required=True'. Refs #1945
---
docs/api-guide/validators.md | 10 ++++++++++
1 file changed, 10 insertions(+)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index 6a0ef4ff..bb073f57 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -93,6 +93,12 @@ The validator should be applied to *serializer classes*, like so:
)
]
+---
+
+**Note**: The `UniqueTogetherValidation` class always imposes an implicit constraint that all the fields it applies to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
+
+---
+
## UniqueForDateValidator
## UniqueForMonthValidator
@@ -146,6 +152,10 @@ If you want the date field to be entirely hidden from the user, then use `Hidden
---
+**Note**: The `UniqueForValidation` classes always imposes an implicit constraint that the fields they are applied to are always treated as required. Fields with `default` values are an exception to this as they always supply a value even when omitted from user input.
+
+---
+
# Writing custom validators
You can use any of Django's existing validators, or write your own custom validators.
--
cgit v1.2.3
From fd7db776addbd5e30f132fe6846ec5c5caab5c40 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 10 Nov 2014 12:32:03 +0000
Subject: Bring UniqueValidator implementation in line with other uniquness
validators.
---
docs/api-guide/validators.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index bb073f57..a50636bc 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -16,9 +16,9 @@ Validation in Django REST framework serializers is handled a little differently
With `ModelForm` the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:
-* It introduces a proper separation of concerns, making your code behaviour more obvious.
-* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behaviour being used for `ModelSerializer` is simple to replicate.
-* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behaviour being called on the model instance.
+* It introduces a proper separation of concerns, making your code behavior more obvious.
+* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behavior being used for `ModelSerializer` is simple to replicate.
+* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.
When you're using `ModelSerializer` all of this is handled automatically for you. If you want to drop down to using a `Serializer` classes instead, then you need to define the validation rules explicitly.
--
cgit v1.2.3
From 0f508c58211051c873aae5a2d1c65a0c595e732a Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 17 Nov 2014 18:36:32 +0000
Subject: Docs for advanced default argument usage. Closes #1945
---
docs/api-guide/validators.md | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index a50636bc..ac2f3248 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -156,6 +156,38 @@ If you want the date field to be entirely hidden from the user, then use `Hidden
---
+# Advanced 'default' argument usage
+
+Validators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that *is* available as input to the validator.
+
+Two patterns that you may want to use for this sort of validation include:
+
+* Using `HiddenField`. This field will be present in `validated_data` but *will not* be used in the serializer output representation.
+* Using a standard field with `read_only=True`, but that also includes a `default=…` argument. This field *will* be used in the serializer output representation, but cannot be set directly by the user.
+
+REST framework includes a couple of defaults that may be useful in this context.
+
+#### CurrentUserDefault
+
+A default class that can be used to represent the current user. In order to use this, the 'request' must have been provided as part of the context dictionary when instantiating the serializer.
+
+ owner = serializers.HiddenField(
+ default=CurrentUserDefault()
+ )
+
+#### CreateOnlyDefault
+
+A default class that can be used to *only set a default argument during create operations*. During updates the field is omitted.
+
+It takes a single argument, which is the default value or callable that should be used during create operations.
+
+ created_at = serializers.DateTimeField(
+ read_only=True,
+ default=CreateOnlyDefault(timezone.now)
+ )
+
+---
+
# Writing custom validators
You can use any of Django's existing validators, or write your own custom validators.
--
cgit v1.2.3
From 8e549a76ea0ff6b44e1dcf08ba733a5fbfc004ed Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Fri, 28 Nov 2014 14:26:03 +0000
Subject: Add 2.x notes and links
---
docs/api-guide/validators.md | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index ac2f3248..f087e191 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -1,5 +1,11 @@
+---
+
+**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available.
+
+---
+
# Validators
> Validators can be useful for re-using validation logic between different types of fields.
--
cgit v1.2.3
From 555c450497e96bf8fed82fc76e70adf907c5c409 Mon Sep 17 00:00:00 2001
From: Tom Christie
Date: Mon, 1 Dec 2014 14:46:47 +0000
Subject: Add missing 'validators.py' link. Closes #2166.
---
docs/api-guide/validators.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index f087e191..8f5a8929 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -1,4 +1,4 @@
-
+source: validators.py
---
--
cgit v1.2.3
From d12de927adaac6018f3e8c232307b76372fe3527 Mon Sep 17 00:00:00 2001
From: José Padilla
Date: Sat, 7 Mar 2015 10:49:56 -0400
Subject: Remove docs for 3.0 banners
---
docs/api-guide/validators.md | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
(limited to 'docs/api-guide/validators.md')
diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md
index 8f5a8929..40ad4857 100644
--- a/docs/api-guide/validators.md
+++ b/docs/api-guide/validators.md
@@ -1,11 +1,5 @@
source: validators.py
----
-
-**Note**: This is the documentation for the **version 3.0** of REST framework. Documentation for [version 2.4](http://tomchristie.github.io/rest-framework-2-docs/) is also available.
-
----
-
# Validators
> Validators can be useful for re-using validation logic between different types of fields.
@@ -33,7 +27,7 @@ When you're using `ModelSerializer` all of this is handled automatically for you
As an example of how REST framework uses explicit validation, we'll take a simple model class that has a field with a uniqueness constraint.
class CustomerReportRecord(models.Model):
- time_raised = models.DateTimeField(default=timezone.now, editable=False)
+ time_raised = models.DateTimeField(default=timezone.now, editable=False)
reference = models.CharField(unique=True, max_length=20)
description = models.TextField()
@@ -43,7 +37,7 @@ Here's a basic `ModelSerializer` that we can use for creating or updating instan
class Meta:
model = CustomerReportRecord
-If we open up the Django shell using `manage.py shell` we can now
+If we open up the Django shell using `manage.py shell` we can now
>>> from project.example.serializers import CustomerReportSerializer
>>> serializer = CustomerReportSerializer()
@@ -204,7 +198,7 @@ A validator may be any callable that raises a `serializers.ValidationError` on f
def even_number(value):
if value % 2 != 0:
- raise serializers.ValidationError('This field must be an even number.')
+ raise serializers.ValidationError('This field must be an even number.')
## Class based
@@ -213,7 +207,7 @@ To write a class based validator, use the `__call__` method. Class based validat
class MultipleOf:
def __init__(self, base):
self.base = base
-
+
def __call__(self, value):
if value % self.base != 0
message = 'This field must be a multiple of %d.' % self.base
--
cgit v1.2.3