aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Dvorak2012-12-23 22:05:16 +0100
committerMichal Dvorak2012-12-23 22:05:16 +0100
commit5d7d51ed9d24e98eaa2d34592db1781d1ea3230f (patch)
tree132af4907a2106c65507bf1e5146324abf59c583
parent5ba2437f2dcb4eb7f9677ff9e393c27af38b071f (diff)
parented09d26fb8da2391cab4b096d276028384438eb6 (diff)
downloaddjango-rest-framework-5d7d51ed9d24e98eaa2d34592db1781d1ea3230f.tar.bz2
Merge remote-tracking branch 'upstream/master'
-rw-r--r--docs/api-guide/generic-views.md12
-rw-r--r--docs/topics/release-notes.md4
-rw-r--r--rest_framework/fields.py7
-rw-r--r--rest_framework/tests/serializer.py32
4 files changed, 48 insertions, 7 deletions
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index 428323b8..27c7d3f6 100644
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -7,11 +7,11 @@
>
> — [Django Documentation][cite]
-One of the key benefits of class based views is the way they allow you to compose bits of reusable behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.
+One of the key benefits of class based views is the way they allow you to compose bits of reusable behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.
The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.
-If the generic views don't suit the needs of your API, you can drop down to using the regular `APIView` class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.
+If the generic views don't suit the needs of your API, you can drop down to using the regular `APIView` class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.
## Examples
@@ -29,7 +29,7 @@ For more complex cases you might also want to override various methods on the vi
model = User
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
-
+
def get_paginate_by(self, queryset):
"""
Use smaller pagination for HTML representations.
@@ -150,14 +150,14 @@ Provides a base view for acting on a single object, by combining REST framework'
* `queryset` - The queryset that should be used when retrieving an object from this view. If unset, defaults to the default queryset manager for `self.model`.
* `pk_kwarg` - The URL kwarg that should be used to look up objects by primary key. Defaults to `'pk'`. [Can only be set to non-default on Django 1.4+]
-* `slug_kwarg` - The URL kwarg that should be used to look up objects by a slug. Defaults to `'slug'`. [Can only be set to non-default on Django 1.4+]
+* `slug_url_kwarg` - The URL kwarg that should be used to look up objects by a slug. Defaults to `'slug'`. [Can only be set to non-default on Django 1.4+]
* `slug_field` - The field on the model that should be used to look up objects by a slug. If used, this should typically be set to a field with `unique=True`. Defaults to `'slug'`.
---
# Mixins
-The mixin classes provide the actions that are used to provide the basic view behaviour. Note that the mixin classes provide action methods rather than defining the handler methods such as `.get()` and `.post()` directly. This allows for more flexible composition of behaviour.
+The mixin classes provide the actions that are used to provide the basic view behaviour. Note that the mixin classes provide action methods rather than defining the handler methods such as `.get()` and `.post()` directly. This allows for more flexible composition of behaviour.
## ListModelMixin
@@ -220,4 +220,4 @@ Should be mixed in with [SingleObjectAPIView].
[CreateModelMixin]: #createmodelmixin
[RetrieveModelMixin]: #retrievemodelmixin
[UpdateModelMixin]: #updatemodelmixin
-[DestroyModelMixin]: #destroymodelmixin \ No newline at end of file
+[DestroyModelMixin]: #destroymodelmixin
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 6dedc3d2..71fa3c03 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -6,6 +6,10 @@
## 2.1.x series
+### Master
+
+* Bugfix: Related fields now respect the required flag, and may be required=False.
+
### 2.1.12
**Date**: 21st Dec 2012
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 398d473f..ca421ace 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -357,7 +357,12 @@ class RelatedField(WritableField):
if self.read_only:
return
- value = data.get(field_name)
+ try:
+ value = data[field_name]
+ except KeyError:
+ if self.required:
+ raise ValidationError(self.error_messages['required'])
+ return
if value in (None, '') and not self.null:
raise ValidationError('Value may not be null')
diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py
index c2a41f88..1c7283ae 100644
--- a/rest_framework/tests/serializer.py
+++ b/rest_framework/tests/serializer.py
@@ -308,6 +308,38 @@ class ModelValidationTests(TestCase):
self.assertFalse(second_serializer.is_valid())
self.assertEqual(second_serializer.errors, {'title': [u'Album with this Title already exists.']})
+ def test_foreign_key_with_partial(self):
+ """
+ Test ModelSerializer validation with partial=True
+
+ Specifically test foreign key validation.
+ """
+
+ album = Album(title='test')
+ album.save()
+
+ class PhotoSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = Photo
+
+ photo_serializer = PhotoSerializer(data={'description': 'test', 'album': album.pk})
+ self.assertTrue(photo_serializer.is_valid())
+ photo = photo_serializer.save()
+
+ # Updating only the album (foreign key)
+ photo_serializer = PhotoSerializer(instance=photo, data={'album': album.pk}, partial=True)
+ self.assertTrue(photo_serializer.is_valid())
+ self.assertTrue(photo_serializer.save())
+
+ # Updating only the description
+ photo_serializer = PhotoSerializer(instance=photo,
+ data={'description': 'new'},
+ partial=True)
+
+ self.assertTrue(photo_serializer.is_valid())
+ self.assertTrue(photo_serializer.save())
+
+
class RegexValidationTest(TestCase):
def test_create_failed(self):