mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			348 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| 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)
 |