mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-03 05:04:31 +03:00
Merge pull request #371 from tomchristie/serializer-fixes
Serializer fixes
This commit is contained in:
commit
b87f01aa54
13
README.md
13
README.md
|
@ -57,9 +57,17 @@ To run the tests.
|
|||
|
||||
# Changelog
|
||||
|
||||
## Master
|
||||
## 2.1.0
|
||||
|
||||
* Minor field improvements (don't stringify dicts, more robust many-pk fields)
|
||||
**Date**: 5th Nov 2012
|
||||
|
||||
**Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
|
||||
|
||||
* **Serializer `instance` and `data` keyword args have their position swapped.**
|
||||
* `queryset` argument is now optional on writable model fields.
|
||||
* Support Django's cache framework.
|
||||
* Minor field improvements. (Don't stringify dicts, more robust many-pk fields.)
|
||||
* Bugfixes (Support choice field in Browseable API)
|
||||
|
||||
## 2.0.2
|
||||
|
||||
|
@ -113,6 +121,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
[0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X
|
||||
[sandbox]: http://restframework.herokuapp.com/
|
||||
[rest-framework-2-announcement]: topics/rest-framework-2-announcement.md
|
||||
[2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion
|
||||
|
||||
[docs]: http://django-rest-framework.org/
|
||||
[urlobject]: https://github.com/zacharyvoase/urlobject
|
||||
|
|
|
@ -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.
|
||||
|
||||
serializer = CommentSerializer(instance=comment)
|
||||
serializer = CommentSerializer(comment)
|
||||
serializer.data
|
||||
# {'email': u'leila@example.com', 'content': u'foo bar', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
|
||||
|
||||
|
@ -65,20 +65,29 @@ Deserialization is similar. First we parse a stream into python native datatype
|
|||
|
||||
...then we restore those native datatypes into a fully populated object instance.
|
||||
|
||||
serializer = CommentSerializer(data)
|
||||
serializer = CommentSerializer(data=data)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.object
|
||||
# <Comment object at 0x10633b2d0>
|
||||
>>> serializer.deserialize('json', stream)
|
||||
|
||||
When deserializing data, we can either create a new instance, or update an existing instance.
|
||||
|
||||
serializer = CommentSerializer(data=data) # Create new instance
|
||||
serializer = CommentSerializer(comment, data=data) # Update `instance`
|
||||
|
||||
## Validation
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
@ -88,16 +97,22 @@ You can specify custom field-level validation by adding `validate_<fieldname>()`
|
|||
|
||||
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]
|
||||
if "Django" not in value:
|
||||
if "django" not in value.lower():
|
||||
raise serializers.ValidationError("Blog post is not about Django")
|
||||
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`.
|
||||
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.
|
||||
|
||||
The generic views provided by REST framework call the `.save()` method when updating or creating entities.
|
||||
|
||||
## Dealing with nested objects
|
||||
|
||||
|
|
|
@ -4,11 +4,18 @@
|
|||
>
|
||||
> — Eric S. Raymond, [The Cathedral and the Bazaar][cite].
|
||||
|
||||
## Master
|
||||
## 2.1.0
|
||||
|
||||
**Date**: 5th Nov 2012
|
||||
|
||||
**Warning**: Please read [this thread][2.1.0-notes] regarding the `instance` and `data` keyword args before updating to 2.1.0.
|
||||
|
||||
* **Serializer `instance` and `data` keyword args have their position swapped.**
|
||||
* `queryset` argument is now optional on writable model fields.
|
||||
* Support Django's cache framework.
|
||||
* Minor field improvements. (Don't stringify dicts, more robust many-pk fields.)
|
||||
* Bugfixes (Support choice field in Browseable API)
|
||||
* Bugfix: Support choice field in Browseable API.
|
||||
* Bugfix: Related fields with `read_only=True` do not require a `queryset` argument.
|
||||
|
||||
## 2.0.2
|
||||
|
||||
|
@ -29,7 +36,7 @@
|
|||
**Date**: 30th Oct 2012
|
||||
|
||||
* **Fix all of the things.** (Well, almost.)
|
||||
* For more information please see the [2.0 migration guide][migration].
|
||||
* For more information please see the [2.0 announcement][announcement].
|
||||
|
||||
---
|
||||
|
||||
|
@ -135,4 +142,5 @@
|
|||
* Initial release.
|
||||
|
||||
[cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
|
||||
[migration]: migration.md
|
||||
[2.1.0-notes]: https://groups.google.com/d/topic/django-rest-framework/Vv2M0CMY9bg/discussion
|
||||
[announcement]: rest-framework-2-announcement.md
|
|
@ -162,7 +162,7 @@ Okay, once we've got a few imports out of the way, let's create a code snippet t
|
|||
|
||||
We've now got a few snippet instances to play with. Let's take a look at serializing one of those instances.
|
||||
|
||||
serializer = SnippetSerializer(instance=snippet)
|
||||
serializer = SnippetSerializer(snippet)
|
||||
serializer.data
|
||||
# {'pk': 1, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly'}
|
||||
|
||||
|
@ -181,7 +181,7 @@ Deserialization is similar. First we parse a stream into python native datatype
|
|||
|
||||
...then we restore those native datatypes into to a fully populated object instance.
|
||||
|
||||
serializer = SnippetSerializer(data)
|
||||
serializer = SnippetSerializer(data=data)
|
||||
serializer.is_valid()
|
||||
# True
|
||||
serializer.object
|
||||
|
@ -240,12 +240,12 @@ The root of our API is going to be a view that supports listing all the existing
|
|||
"""
|
||||
if request.method == 'GET':
|
||||
snippets = Snippet.objects.all()
|
||||
serializer = SnippetSerializer(instance=snippets)
|
||||
serializer = SnippetSerializer(snippets)
|
||||
return JSONResponse(serializer.data)
|
||||
|
||||
elif request.method == 'POST':
|
||||
data = JSONParser().parse(request)
|
||||
serializer = SnippetSerializer(data)
|
||||
serializer = SnippetSerializer(data=data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JSONResponse(serializer.data, status=201)
|
||||
|
@ -267,12 +267,12 @@ We'll also need a view which corresponds to an individual snippet, and can be us
|
|||
return HttpResponse(status=404)
|
||||
|
||||
if request.method == 'GET':
|
||||
serializer = SnippetSerializer(instance=snippet)
|
||||
serializer = SnippetSerializer(snippet)
|
||||
return JSONResponse(serializer.data)
|
||||
|
||||
elif request.method == 'PUT':
|
||||
data = JSONParser().parse(request)
|
||||
serializer = SnippetSerializer(data, instance=snippet)
|
||||
serializer = SnippetSerializer(snippet, data=data)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return JSONResponse(serializer.data)
|
||||
|
|
|
@ -52,11 +52,11 @@ We don't need our `JSONResponse` class anymore, so go ahead and delete that. On
|
|||
"""
|
||||
if request.method == 'GET':
|
||||
snippets = Snippet.objects.all()
|
||||
serializer = SnippetSerializer(instance=snippets)
|
||||
serializer = SnippetSerializer(snippets)
|
||||
return Response(serializer.data)
|
||||
|
||||
elif request.method == 'POST':
|
||||
serializer = SnippetSerializer(request.DATA)
|
||||
serializer = SnippetSerializer(data=request.DATA)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
@ -77,11 +77,11 @@ Our instance view is an improvement over the previous example. It's a little mo
|
|||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
if request.method == 'GET':
|
||||
serializer = SnippetSerializer(instance=snippet)
|
||||
serializer = SnippetSerializer(snippet)
|
||||
return Response(serializer.data)
|
||||
|
||||
elif request.method == 'PUT':
|
||||
serializer = SnippetSerializer(request.DATA, instance=snippet)
|
||||
serializer = SnippetSerializer(snippet, data=request.DATA)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -20,11 +20,11 @@ We'll start by rewriting the root view as a class based view. All this involves
|
|||
"""
|
||||
def get(self, request, format=None):
|
||||
snippets = Snippet.objects.all()
|
||||
serializer = SnippetSerializer(instance=snippets)
|
||||
serializer = SnippetSerializer(snippets)
|
||||
return Response(serializer.data)
|
||||
|
||||
def post(self, request, format=None):
|
||||
serializer = SnippetSerializer(request.DATA)
|
||||
serializer = SnippetSerializer(data=request.DATA)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
|
@ -44,12 +44,12 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
|
|||
|
||||
def get(self, request, pk, format=None):
|
||||
snippet = self.get_object(pk)
|
||||
serializer = SnippetSerializer(instance=snippet)
|
||||
serializer = SnippetSerializer(snippet)
|
||||
return Response(serializer.data)
|
||||
|
||||
def put(self, request, pk, format=None):
|
||||
snippet = self.get_object(pk)
|
||||
serializer = SnippetSerializer(request.DATA, instance=snippet)
|
||||
serializer = SnippetSerializer(snippet, data=request.DATA)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -167,7 +167,7 @@ We've reached the end of our tutorial. If you want to get more involved in the
|
|||
* Join the [REST framework discussion group][group], and help build the community.
|
||||
* Follow the author [on Twitter][twitter] and say hi.
|
||||
|
||||
**Now go build some awesome things.**
|
||||
**Now go build awesome things.**
|
||||
|
||||
[repo]: https://github.com/tomchristie/rest-framework-tutorial
|
||||
[sandbox]: http://restframework.herokuapp.com/
|
||||
|
|
|
@ -40,7 +40,7 @@ class Field(object):
|
|||
|
||||
self.source = source
|
||||
|
||||
def initialize(self, parent):
|
||||
def initialize(self, parent, field_name):
|
||||
"""
|
||||
Called to set up a field prior to field_to_native or field_from_native.
|
||||
|
||||
|
@ -248,7 +248,22 @@ class RelatedField(WritableField):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.queryset = kwargs.pop('queryset', None)
|
||||
super(RelatedField, self).__init__(*args, **kwargs)
|
||||
self.read_only = self.default_read_only
|
||||
self.read_only = kwargs.pop('read_only', self.default_read_only)
|
||||
|
||||
def initialize(self, parent, field_name):
|
||||
super(RelatedField, self).initialize(parent, field_name)
|
||||
if self.queryset is None and not self.read_only:
|
||||
try:
|
||||
manager = getattr(self.parent.opts.model, self.source or field_name)
|
||||
if hasattr(manager, 'related'): # Forward
|
||||
self.queryset = manager.related.model._default_manager.all()
|
||||
else: # Reverse
|
||||
self.queryset = manager.field.rel.to._default_manager.all()
|
||||
except:
|
||||
raise
|
||||
msg = ('Serializer related fields must include a `queryset`' +
|
||||
' argument or set `read_only=True')
|
||||
raise Exception(msg)
|
||||
|
||||
### We need this stuff to make form choices work...
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class GenericAPIView(views.APIView):
|
|||
# TODO: add support for seperate serializer/deserializer
|
||||
serializer_class = self.get_serializer_class()
|
||||
context = self.get_serializer_context()
|
||||
return serializer_class(data, instance=instance, context=context)
|
||||
return serializer_class(instance, data=data, context=context)
|
||||
|
||||
|
||||
class MultipleObjectAPIView(MultipleObjectMixin, GenericAPIView):
|
||||
|
|
|
@ -6,6 +6,15 @@ from django.db import models
|
|||
from django.forms import widgets
|
||||
from django.utils.datastructures import SortedDict
|
||||
from rest_framework.compat import get_concrete_model
|
||||
|
||||
# Note: We do the following so that users of the framework can use this style:
|
||||
#
|
||||
# example_field = serializers.CharField(...)
|
||||
#
|
||||
# This helps keep the seperation between model fields, form fields, and
|
||||
# serializer fields more explicit.
|
||||
|
||||
|
||||
from rest_framework.fields import *
|
||||
|
||||
|
||||
|
@ -82,10 +91,10 @@ class BaseSerializer(Field):
|
|||
_options_class = SerializerOptions
|
||||
_dict_class = SortedDictWithMetadata # Set to unsorted dict for backwards compatability with unsorted implementations.
|
||||
|
||||
def __init__(self, data=None, instance=None, context=None, **kwargs):
|
||||
def __init__(self, instance=None, data=None, context=None, **kwargs):
|
||||
super(BaseSerializer, self).__init__(**kwargs)
|
||||
self.fields = copy.deepcopy(self.base_fields)
|
||||
self.opts = self._options_class(self.Meta)
|
||||
self.fields = copy.deepcopy(self.base_fields)
|
||||
self.parent = None
|
||||
self.root = None
|
||||
|
||||
|
@ -100,13 +109,13 @@ class BaseSerializer(Field):
|
|||
#####
|
||||
# Methods to determine which fields to use when (de)serializing objects.
|
||||
|
||||
def default_fields(self, serialize, obj=None, data=None, nested=False):
|
||||
def default_fields(self, nested=False):
|
||||
"""
|
||||
Return the complete set of default fields for the object, as a dict.
|
||||
"""
|
||||
return {}
|
||||
|
||||
def get_fields(self, serialize, obj=None, data=None, nested=False):
|
||||
def get_fields(self, nested=False):
|
||||
"""
|
||||
Returns the complete set of fields for the object as a dict.
|
||||
|
||||
|
@ -119,10 +128,10 @@ class BaseSerializer(Field):
|
|||
for key, field in self.fields.items():
|
||||
ret[key] = field
|
||||
# Set up the field
|
||||
field.initialize(parent=self)
|
||||
field.initialize(parent=self, field_name=key)
|
||||
|
||||
# Add in the default fields
|
||||
fields = self.default_fields(serialize, obj, data, nested)
|
||||
fields = self.default_fields(nested)
|
||||
for key, val in fields.items():
|
||||
if key not in ret:
|
||||
ret[key] = val
|
||||
|
@ -144,12 +153,12 @@ class BaseSerializer(Field):
|
|||
#####
|
||||
# Field methods - used when the serializer class is itself used as a field.
|
||||
|
||||
def initialize(self, parent):
|
||||
def initialize(self, parent, field_name):
|
||||
"""
|
||||
Same behaviour as usual Field, except that we need to keep track
|
||||
of state so that we can deal with handling maximum depth.
|
||||
"""
|
||||
super(BaseSerializer, self).initialize(parent)
|
||||
super(BaseSerializer, self).initialize(parent, field_name)
|
||||
if parent.opts.depth:
|
||||
self.opts.depth = parent.opts.depth - 1
|
||||
|
||||
|
@ -170,7 +179,7 @@ class BaseSerializer(Field):
|
|||
ret = self._dict_class()
|
||||
ret.fields = {}
|
||||
|
||||
fields = self.get_fields(serialize=True, obj=obj, nested=bool(self.opts.depth))
|
||||
fields = self.get_fields(nested=bool(self.opts.depth))
|
||||
for field_name, field in fields.items():
|
||||
key = self.get_field_key(field_name)
|
||||
value = field.field_to_native(obj, field_name)
|
||||
|
@ -183,7 +192,7 @@ class BaseSerializer(Field):
|
|||
Core of deserialization, together with `restore_object`.
|
||||
Converts a dictionary of data into a dictionary of deserialized fields.
|
||||
"""
|
||||
fields = self.get_fields(serialize=False, data=data, nested=bool(self.opts.depth))
|
||||
fields = self.get_fields(nested=bool(self.opts.depth))
|
||||
reverted_data = {}
|
||||
for field_name, field in fields.items():
|
||||
try:
|
||||
|
@ -198,7 +207,7 @@ class BaseSerializer(Field):
|
|||
Run `validate_<fieldname>()` and `validate()` methods on the serializer
|
||||
"""
|
||||
# TODO: refactor this so we're not determining the fields again
|
||||
fields = self.get_fields(serialize=False, data=attrs, nested=bool(self.opts.depth))
|
||||
fields = self.get_fields(nested=bool(self.opts.depth))
|
||||
|
||||
for field_name, field in fields.items():
|
||||
try:
|
||||
|
@ -237,11 +246,8 @@ class BaseSerializer(Field):
|
|||
"""
|
||||
Serialize objects -> primatives.
|
||||
"""
|
||||
if isinstance(obj, dict):
|
||||
return dict([(key, self.to_native(val))
|
||||
for (key, val) in obj.items()])
|
||||
elif hasattr(obj, '__iter__'):
|
||||
return [self.to_native(item) for item in obj]
|
||||
if hasattr(obj, '__iter__'):
|
||||
return [self.convert_object(item) for item in obj]
|
||||
return self.convert_object(obj)
|
||||
|
||||
def from_native(self, data):
|
||||
|
@ -323,7 +329,7 @@ class ModelSerializer(Serializer):
|
|||
"""
|
||||
_options_class = ModelSerializerOptions
|
||||
|
||||
def default_fields(self, serialize, obj=None, data=None, nested=False):
|
||||
def default_fields(self, nested=False):
|
||||
"""
|
||||
Return all the fields that should be serialized for the model.
|
||||
"""
|
||||
|
@ -360,7 +366,7 @@ class ModelSerializer(Serializer):
|
|||
field = self.get_field(model_field)
|
||||
|
||||
if field:
|
||||
field.initialize(parent=self)
|
||||
field.initialize(parent=self, field_name=model_field.name)
|
||||
ret[model_field.name] = field
|
||||
|
||||
return ret
|
||||
|
|
|
@ -25,7 +25,7 @@ class TestGenericRelations(TestCase):
|
|||
model = Bookmark
|
||||
exclude = ('id',)
|
||||
|
||||
serializer = BookmarkSerializer(instance=self.bookmark)
|
||||
serializer = BookmarkSerializer(self.bookmark)
|
||||
expected = {
|
||||
'tags': [u'django', u'python'],
|
||||
'url': u'https://www.djangoproject.com/'
|
||||
|
|
|
@ -7,12 +7,13 @@ from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, Blo
|
|||
factory = RequestFactory()
|
||||
|
||||
|
||||
class BlogPostCommentSerializer(serializers.Serializer):
|
||||
class BlogPostCommentSerializer(serializers.ModelSerializer):
|
||||
text = serializers.CharField()
|
||||
blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail', queryset=BlogPost.objects.all())
|
||||
blog_post_url = serializers.HyperlinkedRelatedField(source='blog_post', view_name='blogpost-detail')
|
||||
|
||||
def restore_object(self, attrs, instance=None):
|
||||
return BlogPostComment(**attrs)
|
||||
class Meta:
|
||||
model = BlogPostComment
|
||||
fields = ('text', 'blog_post_url')
|
||||
|
||||
|
||||
class BasicList(generics.ListCreateAPIView):
|
||||
|
@ -42,7 +43,7 @@ class ManyToManyDetail(generics.RetrieveAPIView):
|
|||
|
||||
class BlogPostCommentListCreate(generics.ListCreateAPIView):
|
||||
model = BlogPostComment
|
||||
model_serializer_class = BlogPostCommentSerializer
|
||||
serializer_class = BlogPostCommentSerializer
|
||||
|
||||
|
||||
class BlogPostDetail(generics.RetrieveAPIView):
|
||||
|
|
|
@ -74,13 +74,13 @@ class UnitTestPagination(TestCase):
|
|||
self.last_page = paginator.page(3)
|
||||
|
||||
def test_native_pagination(self):
|
||||
serializer = pagination.PaginationSerializer(instance=self.first_page)
|
||||
serializer = pagination.PaginationSerializer(self.first_page)
|
||||
self.assertEquals(serializer.data['count'], 26)
|
||||
self.assertEquals(serializer.data['next'], '?page=2')
|
||||
self.assertEquals(serializer.data['previous'], None)
|
||||
self.assertEquals(serializer.data['results'], self.objects[:10])
|
||||
|
||||
serializer = pagination.PaginationSerializer(instance=self.last_page)
|
||||
serializer = pagination.PaginationSerializer(self.last_page)
|
||||
self.assertEquals(serializer.data['count'], 26)
|
||||
self.assertEquals(serializer.data['next'], None)
|
||||
self.assertEquals(serializer.data['previous'], '?page=2')
|
||||
|
|
|
@ -15,7 +15,7 @@ class ManyToManySource(models.Model):
|
|||
|
||||
|
||||
class ManyToManyTargetSerializer(serializers.ModelSerializer):
|
||||
sources = serializers.ManyPrimaryKeyRelatedField(queryset=ManyToManySource.objects.all())
|
||||
sources = serializers.ManyPrimaryKeyRelatedField()
|
||||
|
||||
class Meta:
|
||||
model = ManyToManyTarget
|
||||
|
@ -63,7 +63,7 @@ class PrimaryKeyManyToManyTests(TestCase):
|
|||
|
||||
def test_many_to_many_retrieve(self):
|
||||
queryset = ManyToManySource.objects.all()
|
||||
serializer = ManyToManySourceSerializer(instance=queryset)
|
||||
serializer = ManyToManySourceSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'source-1', 'targets': [1]},
|
||||
{'id': 2, 'name': u'source-2', 'targets': [1, 2]},
|
||||
|
@ -73,7 +73,7 @@ class PrimaryKeyManyToManyTests(TestCase):
|
|||
|
||||
def test_reverse_many_to_many_retrieve(self):
|
||||
queryset = ManyToManyTarget.objects.all()
|
||||
serializer = ManyToManyTargetSerializer(instance=queryset)
|
||||
serializer = ManyToManyTargetSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]},
|
||||
{'id': 2, 'name': u'target-2', 'sources': [2, 3]},
|
||||
|
@ -84,14 +84,14 @@ class PrimaryKeyManyToManyTests(TestCase):
|
|||
def test_many_to_many_update(self):
|
||||
data = {'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]}
|
||||
instance = ManyToManySource.objects.get(pk=1)
|
||||
serializer = ManyToManySourceSerializer(data, instance=instance)
|
||||
serializer = ManyToManySourceSerializer(instance, data=data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
self.assertEquals(serializer.data, data)
|
||||
serializer.save()
|
||||
|
||||
# Ensure source 1 is updated, and everything else is as expected
|
||||
queryset = ManyToManySource.objects.all()
|
||||
serializer = ManyToManySourceSerializer(instance=queryset)
|
||||
serializer = ManyToManySourceSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'source-1', 'targets': [1, 2, 3]},
|
||||
{'id': 2, 'name': u'source-2', 'targets': [1, 2]},
|
||||
|
@ -102,14 +102,14 @@ class PrimaryKeyManyToManyTests(TestCase):
|
|||
def test_reverse_many_to_many_update(self):
|
||||
data = {'id': 1, 'name': u'target-1', 'sources': [1]}
|
||||
instance = ManyToManyTarget.objects.get(pk=1)
|
||||
serializer = ManyToManyTargetSerializer(data, instance=instance)
|
||||
serializer = ManyToManyTargetSerializer(instance, data=data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
self.assertEquals(serializer.data, data)
|
||||
serializer.save()
|
||||
|
||||
# Ensure target 1 is updated, and everything else is as expected
|
||||
queryset = ManyToManyTarget.objects.all()
|
||||
serializer = ManyToManyTargetSerializer(instance=queryset)
|
||||
serializer = ManyToManyTargetSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'target-1', 'sources': [1]},
|
||||
{'id': 2, 'name': u'target-2', 'sources': [2, 3]},
|
||||
|
@ -130,7 +130,7 @@ class PrimaryKeyForeignKeyTests(TestCase):
|
|||
|
||||
def test_foreign_key_retrieve(self):
|
||||
queryset = ForeignKeySource.objects.all()
|
||||
serializer = ForeignKeySourceSerializer(instance=queryset)
|
||||
serializer = ForeignKeySourceSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'source-1', 'target': 1},
|
||||
{'id': 2, 'name': u'source-2', 'target': 1},
|
||||
|
@ -140,7 +140,7 @@ class PrimaryKeyForeignKeyTests(TestCase):
|
|||
|
||||
def test_reverse_foreign_key_retrieve(self):
|
||||
queryset = ForeignKeyTarget.objects.all()
|
||||
serializer = ForeignKeyTargetSerializer(instance=queryset)
|
||||
serializer = ForeignKeyTargetSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'target-1', 'sources': [1, 2, 3]},
|
||||
{'id': 2, 'name': u'target-2', 'sources': []},
|
||||
|
@ -150,14 +150,14 @@ class PrimaryKeyForeignKeyTests(TestCase):
|
|||
def test_foreign_key_update(self):
|
||||
data = {'id': 1, 'name': u'source-1', 'target': 2}
|
||||
instance = ForeignKeySource.objects.get(pk=1)
|
||||
serializer = ForeignKeySourceSerializer(data, instance=instance)
|
||||
serializer = ForeignKeySourceSerializer(instance, data=data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
self.assertEquals(serializer.data, data)
|
||||
serializer.save()
|
||||
|
||||
# # Ensure source 1 is updated, and everything else is as expected
|
||||
queryset = ForeignKeySource.objects.all()
|
||||
serializer = ForeignKeySourceSerializer(instance=queryset)
|
||||
serializer = ForeignKeySourceSerializer(queryset)
|
||||
expected = [
|
||||
{'id': 1, 'name': u'source-1', 'target': 2},
|
||||
{'id': 2, 'name': u'source-2', 'target': 1},
|
||||
|
@ -172,14 +172,14 @@ class PrimaryKeyForeignKeyTests(TestCase):
|
|||
# def test_reverse_foreign_key_update(self):
|
||||
# data = {'id': 1, 'name': u'target-1', 'sources': [1]}
|
||||
# instance = ForeignKeyTarget.objects.get(pk=1)
|
||||
# serializer = ForeignKeyTargetSerializer(data, instance=instance)
|
||||
# serializer = ForeignKeyTargetSerializer(instance, data=data)
|
||||
# self.assertTrue(serializer.is_valid())
|
||||
# self.assertEquals(serializer.data, data)
|
||||
# serializer.save()
|
||||
|
||||
# # Ensure target 1 is updated, and everything else is as expected
|
||||
# queryset = ForeignKeyTarget.objects.all()
|
||||
# serializer = ForeignKeyTargetSerializer(instance=queryset)
|
||||
# serializer = ForeignKeyTargetSerializer(queryset)
|
||||
# expected = [
|
||||
# {'id': 1, 'name': u'target-1', 'sources': [1]},
|
||||
# {'id': 2, 'name': u'target-2', 'sources': []},
|
||||
|
|
|
@ -87,11 +87,11 @@ class BasicTests(TestCase):
|
|||
self.assertEquals(serializer.data, expected)
|
||||
|
||||
def test_retrieve(self):
|
||||
serializer = CommentSerializer(instance=self.comment)
|
||||
serializer = CommentSerializer(self.comment)
|
||||
self.assertEquals(serializer.data, self.expected)
|
||||
|
||||
def test_create(self):
|
||||
serializer = CommentSerializer(self.data)
|
||||
serializer = CommentSerializer(data=self.data)
|
||||
expected = self.comment
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
self.assertEquals(serializer.object, expected)
|
||||
|
@ -99,25 +99,25 @@ class BasicTests(TestCase):
|
|||
self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
|
||||
|
||||
def test_update(self):
|
||||
serializer = CommentSerializer(self.data, instance=self.comment)
|
||||
serializer = CommentSerializer(self.comment, data=self.data)
|
||||
expected = self.comment
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
self.assertEquals(serializer.object, expected)
|
||||
self.assertTrue(serializer.object is expected)
|
||||
self.assertEquals(serializer.data['sub_comment'], 'And Merry Christmas!')
|
||||
|
||||
|
||||
def test_model_fields_as_expected(self):
|
||||
""" Make sure that the fields returned are the same as defined
|
||||
in the Meta data
|
||||
"""
|
||||
serializer = PersonSerializer(instance=self.person)
|
||||
serializer = PersonSerializer(self.person)
|
||||
self.assertEquals(set(serializer.data.keys()),
|
||||
set(['name', 'age', 'info']))
|
||||
|
||||
def test_field_with_dictionary(self):
|
||||
""" Make sure that dictionaries from fields are left intact
|
||||
"""
|
||||
serializer = PersonSerializer(instance=self.person)
|
||||
serializer = PersonSerializer(self.person)
|
||||
expected = self.person_data
|
||||
self.assertEquals(serializer.data['info'], expected)
|
||||
|
||||
|
@ -138,12 +138,12 @@ class ValidationTests(TestCase):
|
|||
)
|
||||
|
||||
def test_create(self):
|
||||
serializer = CommentSerializer(self.data)
|
||||
serializer = CommentSerializer(data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), False)
|
||||
self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 1000 characters (it has 1001).']})
|
||||
|
||||
def test_update(self):
|
||||
serializer = CommentSerializer(self.data, instance=self.comment)
|
||||
serializer = CommentSerializer(self.comment, data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), False)
|
||||
self.assertEquals(serializer.errors, {'content': [u'Ensure this value has at most 1000 characters (it has 1001).']})
|
||||
|
||||
|
@ -152,7 +152,7 @@ class ValidationTests(TestCase):
|
|||
'content': 'xxx',
|
||||
'created': datetime.datetime(2012, 1, 1)
|
||||
}
|
||||
serializer = CommentSerializer(data, instance=self.comment)
|
||||
serializer = CommentSerializer(self.comment, data=data)
|
||||
self.assertEquals(serializer.is_valid(), False)
|
||||
self.assertEquals(serializer.errors, {'email': [u'This field is required.']})
|
||||
|
||||
|
@ -163,7 +163,7 @@ class ValidationTests(TestCase):
|
|||
'title': 'Some action item',
|
||||
#No 'done' value.
|
||||
}
|
||||
serializer = ActionItemSerializer(data, instance=self.actionitem)
|
||||
serializer = ActionItemSerializer(self.actionitem, data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
self.assertEquals(serializer.errors, {})
|
||||
|
||||
|
@ -183,12 +183,12 @@ class ValidationTests(TestCase):
|
|||
'created': datetime.datetime(2012, 1, 1)
|
||||
}
|
||||
|
||||
serializer = CommentSerializerWithFieldValidator(data)
|
||||
serializer = CommentSerializerWithFieldValidator(data=data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
|
||||
data['content'] = 'This should not validate'
|
||||
|
||||
serializer = CommentSerializerWithFieldValidator(data)
|
||||
serializer = CommentSerializerWithFieldValidator(data=data)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertEquals(serializer.errors, {'content': [u'Test not in value']})
|
||||
|
||||
|
@ -207,12 +207,12 @@ class ValidationTests(TestCase):
|
|||
'created': datetime.datetime(2012, 1, 1)
|
||||
}
|
||||
|
||||
serializer = CommentSerializerWithCrossFieldValidator(data)
|
||||
serializer = CommentSerializerWithCrossFieldValidator(data=data)
|
||||
self.assertTrue(serializer.is_valid())
|
||||
|
||||
data['content'] = 'A comment from foo@bar.com'
|
||||
|
||||
serializer = CommentSerializerWithCrossFieldValidator(data)
|
||||
serializer = CommentSerializerWithCrossFieldValidator(data=data)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
self.assertEquals(serializer.errors, {'non_field_errors': [u'Email address not in content']})
|
||||
|
||||
|
@ -220,7 +220,7 @@ class ValidationTests(TestCase):
|
|||
"""
|
||||
Omitting a value for null-field should validate.
|
||||
"""
|
||||
serializer = PersonSerializer({'name': 'marko'})
|
||||
serializer = PersonSerializer(data={'name': 'marko'})
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
self.assertEquals(serializer.errors, {})
|
||||
|
||||
|
@ -270,7 +270,7 @@ class ManyToManyTests(TestCase):
|
|||
Create an instance of a model with a ManyToMany relationship.
|
||||
"""
|
||||
data = {'rel': [self.anchor.id]}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ManyToManyModel.objects.all()), 2)
|
||||
|
@ -284,7 +284,7 @@ class ManyToManyTests(TestCase):
|
|||
new_anchor = Anchor()
|
||||
new_anchor.save()
|
||||
data = {'rel': [self.anchor.id, new_anchor.id]}
|
||||
serializer = self.serializer_class(data, instance=self.instance)
|
||||
serializer = self.serializer_class(self.instance, data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ManyToManyModel.objects.all()), 1)
|
||||
|
@ -297,7 +297,7 @@ class ManyToManyTests(TestCase):
|
|||
containing no items.
|
||||
"""
|
||||
data = {'rel': []}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ManyToManyModel.objects.all()), 2)
|
||||
|
@ -312,7 +312,7 @@ class ManyToManyTests(TestCase):
|
|||
new_anchor = Anchor()
|
||||
new_anchor.save()
|
||||
data = {'rel': []}
|
||||
serializer = self.serializer_class(data, instance=self.instance)
|
||||
serializer = self.serializer_class(self.instance, data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ManyToManyModel.objects.all()), 1)
|
||||
|
@ -326,7 +326,7 @@ class ManyToManyTests(TestCase):
|
|||
lists (eg form data).
|
||||
"""
|
||||
data = {'rel': ''}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ManyToManyModel.objects.all()), 2)
|
||||
|
@ -364,7 +364,7 @@ class ReadOnlyManyToManyTests(TestCase):
|
|||
new_anchor = Anchor()
|
||||
new_anchor.save()
|
||||
data = {'rel': [self.anchor.id, new_anchor.id]}
|
||||
serializer = self.serializer_class(data, instance=self.instance)
|
||||
serializer = self.serializer_class(self.instance, data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ReadOnlyManyToManyModel.objects.all()), 1)
|
||||
|
@ -380,7 +380,7 @@ class ReadOnlyManyToManyTests(TestCase):
|
|||
new_anchor = Anchor()
|
||||
new_anchor.save()
|
||||
data = {}
|
||||
serializer = self.serializer_class(data, instance=self.instance)
|
||||
serializer = self.serializer_class(self.instance, data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(ReadOnlyManyToManyModel.objects.all()), 1)
|
||||
|
@ -400,7 +400,7 @@ class DefaultValueTests(TestCase):
|
|||
|
||||
def test_create_using_default(self):
|
||||
data = {}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(self.objects.all()), 1)
|
||||
|
@ -409,7 +409,7 @@ class DefaultValueTests(TestCase):
|
|||
|
||||
def test_create_overriding_default(self):
|
||||
data = {'text': 'overridden'}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(self.objects.all()), 1)
|
||||
|
@ -428,7 +428,7 @@ class CallableDefaultValueTests(TestCase):
|
|||
|
||||
def test_create_using_default(self):
|
||||
data = {}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(self.objects.all()), 1)
|
||||
|
@ -437,7 +437,7 @@ class CallableDefaultValueTests(TestCase):
|
|||
|
||||
def test_create_overriding_default(self):
|
||||
data = {'text': 'overridden'}
|
||||
serializer = self.serializer_class(data)
|
||||
serializer = self.serializer_class(data=data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
instance = serializer.save()
|
||||
self.assertEquals(len(self.objects.all()), 1)
|
||||
|
@ -499,11 +499,11 @@ class BlankFieldTests(TestCase):
|
|||
self.data = {'title': ''}
|
||||
|
||||
def test_create_blank_field(self):
|
||||
serializer = self.serializer_class(self.data)
|
||||
serializer = self.serializer_class(data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
|
||||
def test_create_model_blank_field(self):
|
||||
serializer = self.model_serializer_class(self.data)
|
||||
serializer = self.model_serializer_class(data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), True)
|
||||
|
||||
def test_create_not_blank_field(self):
|
||||
|
@ -511,7 +511,7 @@ class BlankFieldTests(TestCase):
|
|||
Test to ensure blank data in a field not marked as blank=True
|
||||
is considered invalid in a non-model serializer
|
||||
"""
|
||||
serializer = self.not_blank_serializer_class(self.data)
|
||||
serializer = self.not_blank_serializer_class(data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), False)
|
||||
|
||||
def test_create_model_not_blank_field(self):
|
||||
|
@ -519,5 +519,5 @@ class BlankFieldTests(TestCase):
|
|||
Test to ensure blank data in a field not marked as blank=True
|
||||
is considered invalid in a model serializer
|
||||
"""
|
||||
serializer = self.not_blank_model_serializer_class(self.data)
|
||||
serializer = self.not_blank_model_serializer_class(data=self.data)
|
||||
self.assertEquals(serializer.is_valid(), False)
|
||||
|
|
Loading…
Reference in New Issue
Block a user