2014-10-30 18:59:16 +03:00
|
|
|
from rest_framework import serializers
|
|
|
|
|
|
|
|
|
|
|
|
class TestNestedSerializer:
|
|
|
|
def setup(self):
|
|
|
|
class NestedSerializer(serializers.Serializer):
|
|
|
|
one = serializers.IntegerField(max_value=10)
|
|
|
|
two = serializers.IntegerField(max_value=10)
|
|
|
|
|
|
|
|
class TestSerializer(serializers.Serializer):
|
|
|
|
nested = NestedSerializer()
|
|
|
|
|
|
|
|
self.Serializer = TestSerializer
|
|
|
|
|
|
|
|
def test_nested_validate(self):
|
|
|
|
input_data = {
|
|
|
|
'nested': {
|
|
|
|
'one': '1',
|
|
|
|
'two': '2',
|
|
|
|
}
|
|
|
|
}
|
|
|
|
expected_data = {
|
|
|
|
'nested': {
|
|
|
|
'one': 1,
|
|
|
|
'two': 2,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serializer = self.Serializer(data=input_data)
|
|
|
|
assert serializer.is_valid()
|
|
|
|
assert serializer.validated_data == expected_data
|
|
|
|
|
|
|
|
def test_nested_serialize_empty(self):
|
|
|
|
expected_data = {
|
|
|
|
'nested': {
|
|
|
|
'one': None,
|
|
|
|
'two': None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serializer = self.Serializer()
|
|
|
|
assert serializer.data == expected_data
|
|
|
|
|
2014-09-03 19:34:09 +04:00
|
|
|
# """
|
|
|
|
# Tests to cover nested serializers.
|
|
|
|
|
|
|
|
# Doesn't cover model serializers.
|
|
|
|
# """
|
|
|
|
# from __future__ import unicode_literals
|
|
|
|
# from django.test import TestCase
|
|
|
|
# from rest_framework import serializers
|
|
|
|
# from . import models
|
|
|
|
|
|
|
|
|
|
|
|
# class WritableNestedSerializerBasicTests(TestCase):
|
|
|
|
# """
|
|
|
|
# Tests for deserializing nested entities.
|
|
|
|
# Basic tests that use serializers that simply restore to dicts.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# def setUp(self):
|
|
|
|
# class TrackSerializer(serializers.Serializer):
|
|
|
|
# order = serializers.IntegerField()
|
|
|
|
# title = serializers.CharField(max_length=100)
|
|
|
|
# duration = serializers.IntegerField()
|
|
|
|
|
|
|
|
# class AlbumSerializer(serializers.Serializer):
|
|
|
|
# album_name = serializers.CharField(max_length=100)
|
|
|
|
# artist = serializers.CharField(max_length=100)
|
|
|
|
# tracks = TrackSerializer(many=True)
|
|
|
|
|
|
|
|
# self.AlbumSerializer = AlbumSerializer
|
|
|
|
|
|
|
|
# def test_nested_validation_success(self):
|
|
|
|
# """
|
|
|
|
# Correct nested serialization should return the input data.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# data = {
|
|
|
|
# 'album_name': 'Discovery',
|
|
|
|
# 'artist': 'Daft Punk',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'One More Time', 'duration': 235},
|
|
|
|
# {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
|
|
|
# {'order': 3, 'title': 'Digital Love', 'duration': 239}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
|
|
|
|
# serializer = self.AlbumSerializer(data=data)
|
|
|
|
# self.assertEqual(serializer.is_valid(), True)
|
|
|
|
# self.assertEqual(serializer.object, data)
|
|
|
|
|
|
|
|
# def test_nested_validation_error(self):
|
|
|
|
# """
|
|
|
|
# Incorrect nested serialization should return appropriate error data.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# data = {
|
|
|
|
# 'album_name': 'Discovery',
|
|
|
|
# 'artist': 'Daft Punk',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'One More Time', 'duration': 235},
|
|
|
|
# {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
|
|
|
# {'order': 3, 'title': 'Digital Love', 'duration': 'foobar'}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
# expected_errors = {
|
|
|
|
# 'tracks': [
|
|
|
|
# {},
|
|
|
|
# {},
|
|
|
|
# {'duration': ['Enter a whole number.']}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
|
|
|
|
# serializer = self.AlbumSerializer(data=data)
|
|
|
|
# self.assertEqual(serializer.is_valid(), False)
|
|
|
|
# self.assertEqual(serializer.errors, expected_errors)
|
|
|
|
|
|
|
|
# def test_many_nested_validation_error(self):
|
|
|
|
# """
|
|
|
|
# Incorrect nested serialization should return appropriate error data
|
|
|
|
# when multiple entities are being deserialized.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# data = [
|
|
|
|
# {
|
|
|
|
# 'album_name': 'Russian Red',
|
|
|
|
# 'artist': 'I Love Your Glasses',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'Cigarettes', 'duration': 121},
|
|
|
|
# {'order': 2, 'title': 'No Past Land', 'duration': 198},
|
|
|
|
# {'order': 3, 'title': 'They Don\'t Believe', 'duration': 191}
|
|
|
|
# ]
|
|
|
|
# },
|
|
|
|
# {
|
|
|
|
# 'album_name': 'Discovery',
|
|
|
|
# 'artist': 'Daft Punk',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'One More Time', 'duration': 235},
|
|
|
|
# {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
|
|
|
# {'order': 3, 'title': 'Digital Love', 'duration': 'foobar'}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
# ]
|
|
|
|
# expected_errors = [
|
|
|
|
# {},
|
|
|
|
# {
|
|
|
|
# 'tracks': [
|
|
|
|
# {},
|
|
|
|
# {},
|
|
|
|
# {'duration': ['Enter a whole number.']}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
# ]
|
|
|
|
|
|
|
|
# serializer = self.AlbumSerializer(data=data, many=True)
|
|
|
|
# self.assertEqual(serializer.is_valid(), False)
|
|
|
|
# self.assertEqual(serializer.errors, expected_errors)
|
|
|
|
|
|
|
|
|
|
|
|
# class WritableNestedSerializerObjectTests(TestCase):
|
|
|
|
# """
|
|
|
|
# Tests for deserializing nested entities.
|
|
|
|
# These tests use serializers that restore to concrete objects.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# def setUp(self):
|
|
|
|
# # Couple of concrete objects that we're going to deserialize into
|
|
|
|
# class Track(object):
|
|
|
|
# def __init__(self, order, title, duration):
|
|
|
|
# self.order, self.title, self.duration = order, title, duration
|
|
|
|
|
|
|
|
# def __eq__(self, other):
|
|
|
|
# return (
|
|
|
|
# self.order == other.order and
|
|
|
|
# self.title == other.title and
|
|
|
|
# self.duration == other.duration
|
|
|
|
# )
|
|
|
|
|
|
|
|
# class Album(object):
|
|
|
|
# def __init__(self, album_name, artist, tracks):
|
|
|
|
# self.album_name, self.artist, self.tracks = album_name, artist, tracks
|
|
|
|
|
|
|
|
# def __eq__(self, other):
|
|
|
|
# return (
|
|
|
|
# self.album_name == other.album_name and
|
|
|
|
# self.artist == other.artist and
|
|
|
|
# self.tracks == other.tracks
|
|
|
|
# )
|
|
|
|
|
|
|
|
# # And their corresponding serializers
|
|
|
|
# class TrackSerializer(serializers.Serializer):
|
|
|
|
# order = serializers.IntegerField()
|
|
|
|
# title = serializers.CharField(max_length=100)
|
|
|
|
# duration = serializers.IntegerField()
|
|
|
|
|
|
|
|
# def restore_object(self, attrs, instance=None):
|
|
|
|
# return Track(attrs['order'], attrs['title'], attrs['duration'])
|
|
|
|
|
|
|
|
# class AlbumSerializer(serializers.Serializer):
|
|
|
|
# album_name = serializers.CharField(max_length=100)
|
|
|
|
# artist = serializers.CharField(max_length=100)
|
|
|
|
# tracks = TrackSerializer(many=True)
|
|
|
|
|
|
|
|
# def restore_object(self, attrs, instance=None):
|
|
|
|
# return Album(attrs['album_name'], attrs['artist'], attrs['tracks'])
|
|
|
|
|
|
|
|
# self.Album, self.Track = Album, Track
|
|
|
|
# self.AlbumSerializer = AlbumSerializer
|
|
|
|
|
|
|
|
# def test_nested_validation_success(self):
|
|
|
|
# """
|
|
|
|
# Correct nested serialization should return a restored object
|
|
|
|
# that corresponds to the input data.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# data = {
|
|
|
|
# 'album_name': 'Discovery',
|
|
|
|
# 'artist': 'Daft Punk',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'One More Time', 'duration': 235},
|
|
|
|
# {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
|
|
|
# {'order': 3, 'title': 'Digital Love', 'duration': 239}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
# expected_object = self.Album(
|
|
|
|
# album_name='Discovery',
|
|
|
|
# artist='Daft Punk',
|
|
|
|
# tracks=[
|
|
|
|
# self.Track(order=1, title='One More Time', duration=235),
|
|
|
|
# self.Track(order=2, title='Aerodynamic', duration=184),
|
|
|
|
# self.Track(order=3, title='Digital Love', duration=239),
|
|
|
|
# ]
|
|
|
|
# )
|
|
|
|
|
|
|
|
# serializer = self.AlbumSerializer(data=data)
|
|
|
|
# self.assertEqual(serializer.is_valid(), True)
|
|
|
|
# self.assertEqual(serializer.object, expected_object)
|
|
|
|
|
|
|
|
# def test_many_nested_validation_success(self):
|
|
|
|
# """
|
|
|
|
# Correct nested serialization should return multiple restored objects
|
|
|
|
# that corresponds to the input data when multiple objects are
|
|
|
|
# being deserialized.
|
|
|
|
# """
|
|
|
|
|
|
|
|
# data = [
|
|
|
|
# {
|
|
|
|
# 'album_name': 'Russian Red',
|
|
|
|
# 'artist': 'I Love Your Glasses',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'Cigarettes', 'duration': 121},
|
|
|
|
# {'order': 2, 'title': 'No Past Land', 'duration': 198},
|
|
|
|
# {'order': 3, 'title': 'They Don\'t Believe', 'duration': 191}
|
|
|
|
# ]
|
|
|
|
# },
|
|
|
|
# {
|
|
|
|
# 'album_name': 'Discovery',
|
|
|
|
# 'artist': 'Daft Punk',
|
|
|
|
# 'tracks': [
|
|
|
|
# {'order': 1, 'title': 'One More Time', 'duration': 235},
|
|
|
|
# {'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
|
|
|
# {'order': 3, 'title': 'Digital Love', 'duration': 239}
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
# ]
|
|
|
|
# expected_object = [
|
|
|
|
# self.Album(
|
|
|
|
# album_name='Russian Red',
|
|
|
|
# artist='I Love Your Glasses',
|
|
|
|
# tracks=[
|
|
|
|
# self.Track(order=1, title='Cigarettes', duration=121),
|
|
|
|
# self.Track(order=2, title='No Past Land', duration=198),
|
|
|
|
# self.Track(order=3, title='They Don\'t Believe', duration=191),
|
|
|
|
# ]
|
|
|
|
# ),
|
|
|
|
# self.Album(
|
|
|
|
# album_name='Discovery',
|
|
|
|
# artist='Daft Punk',
|
|
|
|
# tracks=[
|
|
|
|
# self.Track(order=1, title='One More Time', duration=235),
|
|
|
|
# self.Track(order=2, title='Aerodynamic', duration=184),
|
|
|
|
# self.Track(order=3, title='Digital Love', duration=239),
|
|
|
|
# ]
|
|
|
|
# )
|
|
|
|
# ]
|
|
|
|
|
|
|
|
# serializer = self.AlbumSerializer(data=data, many=True)
|
|
|
|
# self.assertEqual(serializer.is_valid(), True)
|
|
|
|
# self.assertEqual(serializer.object, expected_object)
|
|
|
|
|
|
|
|
|
|
|
|
# class ForeignKeyNestedSerializerUpdateTests(TestCase):
|
|
|
|
# def setUp(self):
|
|
|
|
# class Artist(object):
|
|
|
|
# def __init__(self, name):
|
|
|
|
# self.name = name
|
|
|
|
|
|
|
|
# def __eq__(self, other):
|
|
|
|
# return self.name == other.name
|
|
|
|
|
|
|
|
# class Album(object):
|
|
|
|
# def __init__(self, name, artist):
|
|
|
|
# self.name, self.artist = name, artist
|
|
|
|
|
|
|
|
# def __eq__(self, other):
|
|
|
|
# return self.name == other.name and self.artist == other.artist
|
|
|
|
|
|
|
|
# class ArtistSerializer(serializers.Serializer):
|
|
|
|
# name = serializers.CharField()
|
|
|
|
|
|
|
|
# def restore_object(self, attrs, instance=None):
|
|
|
|
# if instance:
|
|
|
|
# instance.name = attrs['name']
|
|
|
|
# else:
|
|
|
|
# instance = Artist(attrs['name'])
|
|
|
|
# return instance
|
|
|
|
|
|
|
|
# class AlbumSerializer(serializers.Serializer):
|
|
|
|
# name = serializers.CharField()
|
|
|
|
# by = ArtistSerializer(source='artist')
|
|
|
|
|
|
|
|
# def restore_object(self, attrs, instance=None):
|
|
|
|
# if instance:
|
|
|
|
# instance.name = attrs['name']
|
|
|
|
# instance.artist = attrs['artist']
|
|
|
|
# else:
|
|
|
|
# instance = Album(attrs['name'], attrs['artist'])
|
|
|
|
# return instance
|
|
|
|
|
|
|
|
# self.Artist = Artist
|
|
|
|
# self.Album = Album
|
|
|
|
# self.AlbumSerializer = AlbumSerializer
|
|
|
|
|
|
|
|
# def test_create_via_foreign_key_with_source(self):
|
|
|
|
# """
|
|
|
|
# Check that we can both *create* and *update* into objects across
|
|
|
|
# ForeignKeys that have a `source` specified.
|
|
|
|
# Regression test for #1170
|
|
|
|
# """
|
|
|
|
# data = {
|
|
|
|
# 'name': 'Discovery',
|
|
|
|
# 'by': {'name': 'Daft Punk'},
|
|
|
|
# }
|
|
|
|
|
|
|
|
# expected = self.Album(artist=self.Artist('Daft Punk'), name='Discovery')
|
|
|
|
|
|
|
|
# # create
|
|
|
|
# serializer = self.AlbumSerializer(data=data)
|
|
|
|
# self.assertEqual(serializer.is_valid(), True)
|
|
|
|
# self.assertEqual(serializer.object, expected)
|
|
|
|
|
|
|
|
# # update
|
|
|
|
# original = self.Album(artist=self.Artist('The Bats'), name='Free All the Monsters')
|
|
|
|
# serializer = self.AlbumSerializer(instance=original, data=data)
|
|
|
|
# self.assertEqual(serializer.is_valid(), True)
|
|
|
|
# self.assertEqual(serializer.object, expected)
|
|
|
|
|
|
|
|
|
|
|
|
# class NestedModelSerializerUpdateTests(TestCase):
|
|
|
|
# def test_second_nested_level(self):
|
|
|
|
# john = models.Person.objects.create(name="john")
|
|
|
|
|
|
|
|
# post = john.blogpost_set.create(title="Test blog post")
|
|
|
|
# post.blogpostcomment_set.create(text="I hate this blog post")
|
|
|
|
# post.blogpostcomment_set.create(text="I love this blog post")
|
|
|
|
|
|
|
|
# class BlogPostCommentSerializer(serializers.ModelSerializer):
|
|
|
|
# class Meta:
|
|
|
|
# model = models.BlogPostComment
|
|
|
|
|
|
|
|
# class BlogPostSerializer(serializers.ModelSerializer):
|
|
|
|
# comments = BlogPostCommentSerializer(many=True, source='blogpostcomment_set')
|
|
|
|
|
|
|
|
# class Meta:
|
|
|
|
# model = models.BlogPost
|
|
|
|
# fields = ('id', 'title', 'comments')
|
|
|
|
|
|
|
|
# class PersonSerializer(serializers.ModelSerializer):
|
|
|
|
# posts = BlogPostSerializer(many=True, source='blogpost_set')
|
|
|
|
|
|
|
|
# class Meta:
|
|
|
|
# model = models.Person
|
|
|
|
# fields = ('id', 'name', 'age', 'posts')
|
|
|
|
|
|
|
|
# serialize = PersonSerializer(instance=john)
|
|
|
|
# deserialize = PersonSerializer(data=serialize.data, instance=john)
|
|
|
|
# self.assertTrue(deserialize.is_valid())
|
|
|
|
|
|
|
|
# result = deserialize.object
|
|
|
|
# result.save()
|
|
|
|
# self.assertEqual(result.id, john.id)
|