mirror of
https://github.com/django/django.git
synced 2025-01-10 18:36:05 +00:00
Separated natural key serialization tests
This commit is contained in:
parent
6dc7af3e01
commit
d59d3caf32
@ -157,3 +157,24 @@ class Player(models.Model):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string())
|
return '%s (%d) playing for %s' % (self.name, self.rank, self.team.to_string())
|
||||||
|
|
||||||
|
|
||||||
|
# ******** Models for test_natural.py ***********
|
||||||
|
|
||||||
|
class NaturalKeyAnchorManager(models.Manager):
|
||||||
|
def get_by_natural_key(self, data):
|
||||||
|
return self.get(data=data)
|
||||||
|
|
||||||
|
|
||||||
|
class NaturalKeyAnchor(models.Model):
|
||||||
|
objects = NaturalKeyAnchorManager()
|
||||||
|
|
||||||
|
data = models.CharField(max_length=100, unique=True)
|
||||||
|
title = models.CharField(max_length=100, null=True)
|
||||||
|
|
||||||
|
def natural_key(self):
|
||||||
|
return (self.data,)
|
||||||
|
|
||||||
|
|
||||||
|
class FKDataNaturalKey(models.Model):
|
||||||
|
data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True)
|
||||||
|
70
tests/serializers/test_natural.py
Normal file
70
tests/serializers/test_natural.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.core import serializers
|
||||||
|
from django.db import connection
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from .models import FKDataNaturalKey, NaturalKeyAnchor
|
||||||
|
from .tests import register_tests
|
||||||
|
|
||||||
|
|
||||||
|
class NaturalKeySerializerTests(TestCase):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def natural_key_serializer_test(format, self):
|
||||||
|
# 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 natural_key_test(format, self):
|
||||||
|
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.assertEqual(books[1].object.pk, None)
|
||||||
|
|
||||||
|
|
||||||
|
# Dynamically register tests for each serializer
|
||||||
|
register_tests(NaturalKeySerializerTests, 'test_%s_natural_key_serializer', natural_key_serializer_test)
|
||||||
|
register_tests(NaturalKeySerializerTests, 'test_%s_serializer_natural_keys', natural_key_test)
|
@ -10,6 +10,7 @@ from django.test import (
|
|||||||
SimpleTestCase, mock, override_settings, skipUnlessDBFeature,
|
SimpleTestCase, mock, override_settings, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
from django.test.utils import Approximate
|
from django.test.utils import Approximate
|
||||||
|
from django.utils.functional import curry
|
||||||
from django.utils.six import StringIO
|
from django.utils.six import StringIO
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
@ -317,3 +318,18 @@ class SerializersTransactionTestBase(object):
|
|||||||
art_obj = Article.objects.all()[0]
|
art_obj = Article.objects.all()[0]
|
||||||
self.assertEqual(art_obj.categories.all().count(), 1)
|
self.assertEqual(art_obj.categories.all().count(), 1)
|
||||||
self.assertEqual(art_obj.author.name, "Agnes")
|
self.assertEqual(art_obj.author.name, "Agnes")
|
||||||
|
|
||||||
|
|
||||||
|
def register_tests(test_class, method_name, test_func, exclude=None):
|
||||||
|
"""
|
||||||
|
Dynamically create serializer tests to ensure that all registered
|
||||||
|
serializers are automatically tested.
|
||||||
|
"""
|
||||||
|
formats = [
|
||||||
|
f for f in serializers.get_serializer_formats()
|
||||||
|
if (not isinstance(serializers.get_serializer(f), serializers.BadSerializer)
|
||||||
|
and not f == 'geojson'
|
||||||
|
and (exclude is None or f not in exclude))
|
||||||
|
]
|
||||||
|
for format_ in formats:
|
||||||
|
setattr(test_class, method_name % format_, curry(test_func, format_))
|
||||||
|
@ -130,21 +130,6 @@ class Anchor(models.Model):
|
|||||||
ordering = ('id',)
|
ordering = ('id',)
|
||||||
|
|
||||||
|
|
||||||
class NaturalKeyAnchorManager(models.Manager):
|
|
||||||
def get_by_natural_key(self, data):
|
|
||||||
return self.get(data=data)
|
|
||||||
|
|
||||||
|
|
||||||
class NaturalKeyAnchor(models.Model):
|
|
||||||
objects = NaturalKeyAnchorManager()
|
|
||||||
|
|
||||||
data = models.CharField(max_length=100, unique=True)
|
|
||||||
title = models.CharField(max_length=100, null=True)
|
|
||||||
|
|
||||||
def natural_key(self):
|
|
||||||
return (self.data,)
|
|
||||||
|
|
||||||
|
|
||||||
class UniqueAnchor(models.Model):
|
class UniqueAnchor(models.Model):
|
||||||
"""This is a model that can be used as
|
"""This is a model that can be used as
|
||||||
something for other models to point at"""
|
something for other models to point at"""
|
||||||
@ -156,10 +141,6 @@ class FKData(models.Model):
|
|||||||
data = models.ForeignKey(Anchor, models.SET_NULL, null=True)
|
data = models.ForeignKey(Anchor, models.SET_NULL, null=True)
|
||||||
|
|
||||||
|
|
||||||
class FKDataNaturalKey(models.Model):
|
|
||||||
data = models.ForeignKey(NaturalKeyAnchor, models.SET_NULL, null=True)
|
|
||||||
|
|
||||||
|
|
||||||
class M2MData(models.Model):
|
class M2MData(models.Model):
|
||||||
data = models.ManyToManyField(Anchor)
|
data = models.ManyToManyField(Anchor)
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@ from .models import (
|
|||||||
BooleanData, BooleanPKData, CharData, CharPKData, ComplexModel, DateData,
|
BooleanData, BooleanPKData, CharData, CharPKData, ComplexModel, DateData,
|
||||||
DateTimeData, DecimalData, DecimalPKData, EmailData, EmailPKData,
|
DateTimeData, DecimalData, DecimalPKData, EmailData, EmailPKData,
|
||||||
ExplicitInheritBaseModel, FileData, FilePathData, FilePathPKData, FKData,
|
ExplicitInheritBaseModel, FileData, FilePathData, FilePathPKData, FKData,
|
||||||
FKDataNaturalKey, FKDataToField, FKDataToO2O, FKSelfData, FKToUUID,
|
FKDataToField, FKDataToO2O, FKSelfData, FKToUUID,
|
||||||
FloatData, FloatPKData, GenericData, GenericIPAddressData,
|
FloatData, FloatPKData, GenericData, GenericIPAddressData,
|
||||||
GenericIPAddressPKData, InheritAbstractModel, InheritBaseModel,
|
GenericIPAddressPKData, InheritAbstractModel, InheritBaseModel,
|
||||||
IntegerData, IntegerPKData, Intermediate, LengthModel, M2MData,
|
IntegerData, IntegerPKData, Intermediate, LengthModel, M2MData,
|
||||||
M2MIntermediateData, M2MSelfData, ModifyingSaveData, NaturalKeyAnchor,
|
M2MIntermediateData, M2MSelfData, ModifyingSaveData,
|
||||||
NullBooleanData, O2OData, PositiveIntegerData, PositiveIntegerPKData,
|
NullBooleanData, O2OData, PositiveIntegerData, PositiveIntegerPKData,
|
||||||
PositiveSmallIntegerData, PositiveSmallIntegerPKData, ProxyBaseModel,
|
PositiveSmallIntegerData, PositiveSmallIntegerPKData, ProxyBaseModel,
|
||||||
ProxyProxyBaseModel, SlugData, SlugPKData, SmallData, SmallPKData, Tag,
|
ProxyProxyBaseModel, SlugData, SlugPKData, SmallData, SmallPKData, Tag,
|
||||||
@ -367,11 +367,6 @@ The end."""),
|
|||||||
(data_obj, 1005, LengthModel, 1),
|
(data_obj, 1005, LengthModel, 1),
|
||||||
]
|
]
|
||||||
|
|
||||||
natural_key_test_data = [
|
|
||||||
(data_obj, 1100, NaturalKeyAnchor, "Natural Key Anghor"),
|
|
||||||
(fk_obj, 1101, FKDataNaturalKey, 1100),
|
|
||||||
(fk_obj, 1102, FKDataNaturalKey, None),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Because Oracle treats the empty string as NULL, Oracle is expected to fail
|
# Because Oracle treats the empty string as NULL, Oracle is expected to fail
|
||||||
# when field.empty_strings_allowed is True and the value is None; skip these
|
# when field.empty_strings_allowed is True and the value is None; skip these
|
||||||
@ -391,9 +386,6 @@ if connection.features.allows_auto_pk_0:
|
|||||||
(fk_obj, 465, FKData, 0),
|
(fk_obj, 465, FKData, 0),
|
||||||
])
|
])
|
||||||
|
|
||||||
# Dynamically create serializer tests to ensure that all
|
|
||||||
# registered serializers are automatically tested.
|
|
||||||
|
|
||||||
|
|
||||||
@skipUnlessDBFeature('can_defer_constraint_checks')
|
@skipUnlessDBFeature('can_defer_constraint_checks')
|
||||||
class SerializerTests(TestCase):
|
class SerializerTests(TestCase):
|
||||||
@ -465,36 +457,6 @@ def serializerTest(format, self):
|
|||||||
self.assertEqual(count, klass.objects.count())
|
self.assertEqual(count, klass.objects.count())
|
||||||
|
|
||||||
|
|
||||||
def naturalKeySerializerTest(format, self):
|
|
||||||
# Create all the objects defined in the test data
|
|
||||||
objects = []
|
|
||||||
instance_count = {}
|
|
||||||
for (func, pk, klass, datum) in natural_key_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()
|
|
||||||
|
|
||||||
# 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 (func, pk, klass, datum) in natural_key_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 fieldsTest(format, self):
|
def fieldsTest(format, self):
|
||||||
obj = ComplexModel(field1='first', field2='second', field3='third')
|
obj = ComplexModel(field1='first', field2='second', field3='third')
|
||||||
obj.save_base(raw=True)
|
obj.save_base(raw=True)
|
||||||
@ -527,39 +489,9 @@ def streamTest(format, self):
|
|||||||
self.assertEqual(string_data, stream.content.decode('utf-8'))
|
self.assertEqual(string_data, stream.content.decode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
def naturalKeyTest(format, self):
|
|
||||||
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.assertEqual(books[1].object.pk, None)
|
|
||||||
|
|
||||||
|
|
||||||
for format in [f for f in serializers.get_serializer_formats()
|
for format in [f for f in serializers.get_serializer_formats()
|
||||||
if not isinstance(serializers.get_serializer(f), serializers.BadSerializer) and not f == 'geojson']:
|
if not isinstance(serializers.get_serializer(f), serializers.BadSerializer) and not f == 'geojson']:
|
||||||
setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
|
setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format))
|
||||||
setattr(SerializerTests, 'test_' + format + '_natural_key_serializer', curry(naturalKeySerializerTest, format))
|
|
||||||
setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
|
setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format))
|
||||||
setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format))
|
|
||||||
if format != 'python':
|
if format != 'python':
|
||||||
setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))
|
setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))
|
||||||
|
Loading…
Reference in New Issue
Block a user