def test_serialize_range_with_null(self): instance = RangesModel(ints=NumericRange(None, 10)) data = serializers.serialize('json', [instance]) new_instance = list(serializers.deserialize('json', data))[0].object self.assertEqual(new_instance.ints, NumericRange(None, 10)) instance = RangesModel(ints=NumericRange(10, None)) data = serializers.serialize('json', [instance]) new_instance = list(serializers.deserialize('json', data))[0].object self.assertEqual(new_instance.ints, NumericRange(10, None))
def natural_pk_mti_test(self, format): """ If serializing objects in a multi-table inheritance relationship using natural primary keys, the natural foreign key for the parent is output in the fields of the child so it's possible to relate the child to the parent when deserializing. """ child_1 = Child.objects.create(parent_data='1', child_data='1') child_2 = Child.objects.create(parent_data='2', child_data='2') string_data = serializers.serialize( format, [child_1.parent_ptr, child_2.parent_ptr, child_2, child_1], use_natural_foreign_keys=True, use_natural_primary_keys=True, ) child_1.delete() child_2.delete() for obj in serializers.deserialize(format, string_data): obj.save() children = Child.objects.all() self.assertEqual(len(children), 2) for child in children: # If it's possible to find the superclass from the subclass and it's # the correct superclass, it's working. self.assertEqual(child.child_data, child.parent_data)
def natural_key_serializer_test(self, format): # Create all the objects defined in the test data with connection.constraint_checks_disabled(): objects = [ NaturalKeyAnchor.objects.create(id=1100, data="Natural Key Anghor"), FKDataNaturalKey.objects.create(id=1101, data_id=1100), FKDataNaturalKey.objects.create(id=1102, data_id=None), ] # Serialize the test database serialized_data = serializers.serialize(format, objects, indent=2, use_natural_foreign_keys=True) for obj in serializers.deserialize(format, serialized_data): obj.save() # Assert that the deserialized data is the same # as the original source for obj in objects: instance = obj.__class__.objects.get(id=obj.pk) self.assertEqual( obj.data, instance.data, "Objects with PK=%d not equal; expected '%s' (%s), got '%s' (%s)" % ( obj.pk, obj.data, type(obj.data), instance, type(instance.data), ))
def test_loading(self): instance = list(serializers.deserialize('json', self.test_data))[0].object self.assertEqual(instance.ints, NumericRange(0, 10)) self.assertEqual(instance.floats, NumericRange(empty=True)) self.assertIsNone(instance.bigints) self.assertEqual(instance.dates, DateRange(self.lower_date, self.upper_date)) self.assertEqual(instance.timestamps, DateTimeTZRange(self.lower_dt, self.upper_dt))
def test_dump_and_load_m2m_simple(self): """ Test serializing and deserializing back models with simple M2M relations """ a = M2MSimpleA.objects.create(data="a") b1 = M2MSimpleB.objects.create(data="b1") b2 = M2MSimpleB.objects.create(data="b2") a.b_set.add(b1) a.b_set.add(b2) out = StringIO() management.call_command( 'dumpdata', 'fixtures_regress.M2MSimpleA', 'fixtures_regress.M2MSimpleB', use_natural_foreign_keys=True, stdout=out, ) for model in [M2MSimpleA, M2MSimpleB]: model.objects.all().delete() objects = serializers.deserialize("json", out.getvalue()) for obj in objects: obj.save() new_a = M2MSimpleA.objects.get_by_natural_key("a") self.assertQuerysetEqual(new_a.b_set.all(), ["<M2MSimpleB: b1>", "<M2MSimpleB: b2>"], ordered=False)
def forward_ref_m2m_test(self, format): t1 = NaturalKeyThing.objects.create(key='t1') t2 = NaturalKeyThing.objects.create(key='t2') t3 = NaturalKeyThing.objects.create(key='t3') t1.other_things.set([t2, t3]) string_data = serializers.serialize( format, [t1, t2, t3], use_natural_primary_keys=True, use_natural_foreign_keys=True, ) NaturalKeyThing.objects.all().delete() objs_with_deferred_fields = [] for obj in serializers.deserialize(format, string_data, handle_forward_references=True): obj.save() if obj.deferred_fields: objs_with_deferred_fields.append(obj) for obj in objs_with_deferred_fields: obj.save_deferred_fields() t1 = NaturalKeyThing.objects.get(key='t1') t2 = NaturalKeyThing.objects.get(key='t2') t3 = NaturalKeyThing.objects.get(key='t3') self.assertCountEqual(t1.other_things.all(), [t2, t3])
def natural_key_test(self, format): book1 = { 'data': '978-1590597255', 'title': 'The Definitive Guide to Django: Web Development Done Right', } book2 = {'data': '978-1590599969', 'title': 'Practical Django Projects'} # Create the books. adrian = NaturalKeyAnchor.objects.create(**book1) james = NaturalKeyAnchor.objects.create(**book2) # Serialize the books. string_data = serializers.serialize( format, NaturalKeyAnchor.objects.all(), indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True, ) # Delete one book (to prove that the natural key generation will only # restore the primary keys of books found in the database via the # get_natural_key manager method). james.delete() # Deserialize and test. books = list(serializers.deserialize(format, string_data)) self.assertEqual(len(books), 2) self.assertEqual(books[0].object.title, book1['title']) self.assertEqual(books[0].object.pk, adrian.pk) self.assertEqual(books[1].object.title, book2['title']) self.assertIsNone(books[1].object.pk)
def test_helpful_error_message_for_many2many_non_natural(self): """ Invalid many-to-many keys should throw a helpful error message. """ test_string = """[{ "pk": 1, "model": "serializers.article", "fields": { "author": 1, "headline": "Unknown many to many", "pub_date": "2014-09-15T10:35:00", "categories": [1, "doesnotexist"] } }, { "pk": 1, "model": "serializers.author", "fields": { "name": "Agnes" } }, { "pk": 1, "model": "serializers.category", "fields": { "name": "Reference" } }]""" expected = "(serializers.article:pk=1) field_value was 'doesnotexist'" with self.assertRaisesMessage(DeserializationError, expected): list(serializers.deserialize('json', test_string))
def test_deserialize_force_insert(self): """Deserialized content can be saved with force_insert as a parameter.""" serial_str = serializers.serialize(self.serializer_name, [self.a1]) deserial_obj = list(serializers.deserialize(self.serializer_name, serial_str))[0] with mock.patch('djmodels.db.models.Model') as mock_model: deserial_obj.save(force_insert=False) mock_model.save_base.assert_called_with(deserial_obj.object, raw=True, using=None, force_insert=False)
def serializerTest(self, format): # Create all the objects defined in the test data objects = [] instance_count = {} for (func, pk, klass, datum) in test_data: with connection.constraint_checks_disabled(): objects.extend(func[0](pk, klass, datum)) # Get a count of the number of objects created for each class for klass in instance_count: instance_count[klass] = klass.objects.count() # Add the generic tagged objects to the object list objects.extend(Tag.objects.all()) # Serialize the test database serialized_data = serializers.serialize(format, objects, indent=2) for obj in serializers.deserialize(format, serialized_data): obj.save() # Assert that the deserialized data is the same # as the original source for (func, pk, klass, datum) in test_data: func[1](self, pk, klass, datum) # Assert that the number of objects deserialized is the # same as the number that was serialized. for klass, count in instance_count.items(): self.assertEqual(count, klass.objects.count())
def test_float_serialization(self): """Float values serialize and deserialize intact""" sc = Score(score=3.4) sc.save() serial_str = serializers.serialize(self.serializer_name, [sc]) deserial_objs = list(serializers.deserialize(self.serializer_name, serial_str)) self.assertEqual(deserial_objs[0].object.score, Approximate(3.4, places=1))
def deserialize_db_from_string(self, data): """ Reload the database with data from a string generated by the serialize_db_to_string() method. """ data = StringIO(data) for obj in serializers.deserialize("json", data, using=self.connection.alias): obj.save()
def test_pkless_serialized_strings(self): """ Serialized strings without PKs can be turned into models """ deserial_objs = list(serializers.deserialize(self.serializer_name, self.pkless_str)) for obj in deserial_objs: self.assertFalse(obj.object.id) obj.save() self.assertEqual(Category.objects.all().count(), 5)
def test_no_dtd(self): """ The XML deserializer shouldn't allow a DTD. This is the most straightforward way to prevent all entity definitions and avoid both external entities and entity-expansion attacks. """ xml = '<?xml version="1.0" standalone="no"?><!DOCTYPE example SYSTEM "http://example.com/example.dtd">' with self.assertRaises(DTDForbidden): next(serializers.deserialize('xml', xml))
def test_one_to_one_as_pk(self): """ If you use your own primary key field (such as a OneToOneField), it doesn't appear in the serialized field list - it replaces the pk identifier. """ AuthorProfile.objects.create(author=self.joe, date_of_birth=datetime(1970, 1, 1)) serial_str = serializers.serialize(self.serializer_name, AuthorProfile.objects.all()) self.assertFalse(self._get_field_values(serial_str, 'author')) for obj in serializers.deserialize(self.serializer_name, serial_str): self.assertEqual(obj.object.pk, self.joe.pk)
def test_serialize_with_null_pk(self): """ Serialized data with no primary key results in a model instance with no id """ category = Category(name="Reference") serial_str = serializers.serialize(self.serializer_name, [category]) pk_value = self._get_pk_values(serial_str)[0] self.assertFalse(pk_value) cat_obj = list(serializers.deserialize(self.serializer_name, serial_str))[0].object self.assertIsNone(cat_obj.id)
def test_serialize_specific_fields(self): obj = ComplexModel(field1='first', field2='second', field3='third') obj.save_base(raw=True) # Serialize then deserialize the test database serialized_data = serializers.serialize( self.serializer_name, [obj], indent=2, fields=('field1', 'field3') ) result = next(serializers.deserialize(self.serializer_name, serialized_data)) # The deserialized object contains data in only the serialized fields. self.assertEqual(result.object.field1, 'first') self.assertEqual(result.object.field2, '') self.assertEqual(result.object.field3, 'third')
def test_custom_field_serialization(self): """Custom fields serialize and deserialize intact""" team_str = "Spartak Moskva" player = Player() player.name = "Soslan Djanaev" player.rank = 1 player.team = Team(team_str) player.save() serial_str = serializers.serialize(self.serializer_name, Player.objects.all()) team = self._get_field_values(serial_str, "team") self.assertTrue(team) self.assertEqual(team[0], team_str) deserial_objs = list(serializers.deserialize(self.serializer_name, serial_str)) self.assertEqual(deserial_objs[0].object.team.to_string(), player.team.to_string())
def test_serialize_unicode(self): """Unicode makes the roundtrip intact""" actor_name = "Za\u017c\u00f3\u0142\u0107" movie_title = 'G\u0119\u015bl\u0105 ja\u017a\u0144' ac = Actor(name=actor_name) mv = Movie(title=movie_title, actor=ac) ac.save() mv.save() serial_str = serializers.serialize(self.serializer_name, [mv]) self.assertEqual(self._get_field_values(serial_str, "title")[0], movie_title) self.assertEqual(self._get_field_values(serial_str, "actor")[0], actor_name) obj_list = list(serializers.deserialize(self.serializer_name, serial_str)) mv_obj = obj_list[0].object self.assertEqual(mv_obj.title, movie_title)
def test_helpful_error_message_invalid_pk(self): """ If there is an invalid primary key, the error message should contain the model associated with it. """ test_string = """[{ "pk": "badpk", "model": "serializers.player", "fields": { "name": "Bob", "rank": 1, "team": "Team" } }]""" with self.assertRaisesMessage(DeserializationError, "(serializers.player:pk=badpk)"): list(serializers.deserialize('json', test_string))
def test_helpful_error_message_invalid_field(self): """ If there is an invalid field value, the error message should contain the model associated with it. """ test_string = """[{ "pk": "1", "model": "serializers.player", "fields": { "name": "Bob", "rank": "invalidint", "team": "Team" } }]""" expected = "(serializers.player:pk=1) field_value was 'invalidint'" with self.assertRaisesMessage(DeserializationError, expected): list(serializers.deserialize('json', test_string))
def test_forward_refs(self): """ Objects ids can be referenced before they are defined in the serialization data. """ # The deserialization process needs to run in a transaction in order # to test forward reference handling. with transaction.atomic(): objs = serializers.deserialize(self.serializer_name, self.fwd_ref_str) with connection.constraint_checks_disabled(): for obj in objs: obj.save() for model_cls in (Category, Author, Article): self.assertEqual(model_cls.objects.all().count(), 1) art_obj = Article.objects.all()[0] self.assertEqual(art_obj.categories.all().count(), 1) self.assertEqual(art_obj.author.name, "Agnes")
def test_altering_serialized_output(self): """ The ability to create new objects by modifying serialized content. """ old_headline = "Poker has no place on ESPN" new_headline = "Poker has no place on television" serial_str = serializers.serialize(self.serializer_name, Article.objects.all()) serial_str = serial_str.replace(old_headline, new_headline) models = list(serializers.deserialize(self.serializer_name, serial_str)) # Prior to saving, old headline is in place self.assertTrue(Article.objects.filter(headline=old_headline)) self.assertFalse(Article.objects.filter(headline=new_headline)) for model in models: model.save() # After saving, new headline is in place self.assertTrue(Article.objects.filter(headline=new_headline)) self.assertFalse(Article.objects.filter(headline=old_headline))
def test_helpful_error_message_for_foreign_keys(self): """ Invalid foreign keys with a natural key should throw a helpful error message, such as what the failing key is. """ test_string = """[{ "pk": 1, "model": "serializers.category", "fields": { "name": "Unknown foreign key", "meta_data": [ "doesnotexist", "metadata" ] } }]""" key = ["doesnotexist", "metadata"] expected = "(serializers.category:pk=1) field_value was '%r'" % key with self.assertRaisesMessage(DeserializationError, expected): list(serializers.deserialize('json', test_string))
def test_helpful_error_message_for_many2many_natural1(self): """ Invalid many-to-many keys should throw a helpful error message. This tests the code path where one of a list of natural keys is invalid. """ test_string = """[{ "pk": 1, "model": "serializers.categorymetadata", "fields": { "kind": "author", "name": "meta1", "value": "Agnes" } }, { "pk": 1, "model": "serializers.article", "fields": { "author": 1, "headline": "Unknown many to many", "pub_date": "2014-09-15T10:35:00", "meta_data": [ ["author", "meta1"], ["doesnotexist", "meta1"], ["author", "meta1"] ] } }, { "pk": 1, "model": "serializers.author", "fields": { "name": "Agnes" } }]""" key = ["doesnotexist", "meta1"] expected = "(serializers.article:pk=1) field_value was '%r'" % key with self.assertRaisesMessage(DeserializationError, expected): for obj in serializers.deserialize('json', test_string): obj.save()
def forward_ref_fk_with_error_test(self, format): t1 = NaturalKeyThing.objects.create(key='t1') t2 = NaturalKeyThing.objects.create(key='t2', other_thing=t1) t1.other_thing = t2 t1.save() string_data = serializers.serialize( format, [t1], use_natural_primary_keys=True, use_natural_foreign_keys=True, ) NaturalKeyThing.objects.all().delete() objs_with_deferred_fields = [] for obj in serializers.deserialize(format, string_data, handle_forward_references=True): obj.save() if obj.deferred_fields: objs_with_deferred_fields.append(obj) obj = objs_with_deferred_fields[0] msg = 'NaturalKeyThing matching query does not exist' with self.assertRaisesMessage(serializers.base.DeserializationError, msg): obj.save_deferred_fields()
def test_helpful_error_message_for_many2many_natural2(self): """ Invalid many-to-many keys should throw a helpful error message. This tests the code path where a natural many-to-many key has only a single value. """ test_string = """[{ "pk": 1, "model": "serializers.article", "fields": { "author": 1, "headline": "Unknown many to many", "pub_date": "2014-09-15T10:35:00", "meta_data": [1, "doesnotexist"] } }, { "pk": 1, "model": "serializers.categorymetadata", "fields": { "kind": "author", "name": "meta1", "value": "Agnes" } }, { "pk": 1, "model": "serializers.author", "fields": { "name": "Agnes" } }]""" expected = "(serializers.article:pk=1) field_value was 'doesnotexist'" with self.assertRaisesMessage(DeserializationError, expected): for obj in serializers.deserialize('json', test_string, ignore=False): obj.save()
def test_roundtrip_with_null(self): instance = HStoreModel(field={'a': 'b', 'c': None}) data = serializers.serialize('json', [instance]) new_instance = list(serializers.deserialize('json', data))[0].object self.assertEqual(instance.field, new_instance.field)
def test_loading(self): instance = list(serializers.deserialize('json', self.test_data))[0].object self.assertEqual(instance.field, {'a': 'b'}) self.assertEqual(instance.array_field, [{'a': 'b'}, {'b': 'a'}])
def test_deserialization_exception(self): """ GeoJSON cannot be deserialized. """ with self.assertRaises(serializers.base.SerializerDoesNotExist): serializers.deserialize('geojson', '{}')