tests.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. from __future__ import unicode_literals
  2. import datetime
  3. import pickle
  4. import unittest
  5. from django.db import models
  6. from django.test import TestCase
  7. from django.utils import six
  8. from django.utils.version import get_version
  9. from .models import Container, Event, Group, Happening, M2MModel
  10. class PickleabilityTestCase(TestCase):
  11. def setUp(self):
  12. Happening.objects.create() # make sure the defaults are working (#20158)
  13. def assert_pickles(self, qs):
  14. self.assertEqual(list(pickle.loads(pickle.dumps(qs))), list(qs))
  15. def test_related_field(self):
  16. g = Group.objects.create(name="Ponies Who Own Maybachs")
  17. self.assert_pickles(Event.objects.filter(group=g.id))
  18. def test_datetime_callable_default_all(self):
  19. self.assert_pickles(Happening.objects.all())
  20. def test_datetime_callable_default_filter(self):
  21. self.assert_pickles(Happening.objects.filter(when=datetime.datetime.now()))
  22. def test_string_as_default(self):
  23. self.assert_pickles(Happening.objects.filter(name="test"))
  24. def test_standalone_method_as_default(self):
  25. self.assert_pickles(Happening.objects.filter(number1=1))
  26. @unittest.skipIf(six.PY2, "Field doesn't exist on Python 2.")
  27. def test_staticmethod_as_default(self):
  28. self.assert_pickles(Happening.objects.filter(number2=1))
  29. def test_filter_reverse_fk(self):
  30. self.assert_pickles(Group.objects.filter(event=1))
  31. def test_doesnotexist_exception(self):
  32. # Ticket #17776
  33. original = Event.DoesNotExist("Doesn't exist")
  34. unpickled = pickle.loads(pickle.dumps(original))
  35. # Exceptions are not equal to equivalent instances of themselves, so
  36. # can't just use assertEqual(original, unpickled)
  37. self.assertEqual(original.__class__, unpickled.__class__)
  38. self.assertEqual(original.args, unpickled.args)
  39. def test_manager_pickle(self):
  40. pickle.loads(pickle.dumps(Happening.objects))
  41. def test_model_pickle(self):
  42. """
  43. Test that a model not defined on module level is picklable.
  44. """
  45. original = Container.SomeModel(pk=1)
  46. dumped = pickle.dumps(original)
  47. reloaded = pickle.loads(dumped)
  48. self.assertEqual(original, reloaded)
  49. # Also, deferred dynamic model works
  50. Container.SomeModel.objects.create(somefield=1)
  51. original = Container.SomeModel.objects.defer('somefield')[0]
  52. dumped = pickle.dumps(original)
  53. reloaded = pickle.loads(dumped)
  54. self.assertEqual(original, reloaded)
  55. self.assertEqual(original.somefield, reloaded.somefield)
  56. def test_model_pickle_m2m(self):
  57. """
  58. Test intentionally the automatically created through model.
  59. """
  60. m1 = M2MModel.objects.create()
  61. g1 = Group.objects.create(name='foof')
  62. m1.groups.add(g1)
  63. m2m_through = M2MModel._meta.get_field('groups').remote_field.through
  64. original = m2m_through.objects.get()
  65. dumped = pickle.dumps(original)
  66. reloaded = pickle.loads(dumped)
  67. self.assertEqual(original, reloaded)
  68. def test_model_pickle_dynamic(self):
  69. class Meta:
  70. proxy = True
  71. dynclass = type(str("DynamicEventSubclass"), (Event, ),
  72. {'Meta': Meta, '__module__': Event.__module__})
  73. original = dynclass(pk=1)
  74. dumped = pickle.dumps(original)
  75. reloaded = pickle.loads(dumped)
  76. self.assertEqual(original, reloaded)
  77. self.assertIs(reloaded.__class__, dynclass)
  78. def test_specialized_queryset(self):
  79. self.assert_pickles(Happening.objects.values('name'))
  80. self.assert_pickles(Happening.objects.values('name').dates('when', 'year'))
  81. # With related field (#14515)
  82. self.assert_pickles(
  83. Event.objects.select_related('group').order_by('title').values_list('title', 'group__name')
  84. )
  85. def test_pickle_prefetch_related_idempotence(self):
  86. g = Group.objects.create(name='foo')
  87. groups = Group.objects.prefetch_related('event_set')
  88. # First pickling
  89. groups = pickle.loads(pickle.dumps(groups))
  90. self.assertQuerysetEqual(groups, [g], lambda x: x)
  91. # Second pickling
  92. groups = pickle.loads(pickle.dumps(groups))
  93. self.assertQuerysetEqual(groups, [g], lambda x: x)
  94. def test_pickle_prefetch_related_with_m2m_and_objects_deletion(self):
  95. """
  96. #24831 -- Cached properties on ManyToOneRel created in QuerySet.delete()
  97. caused subsequent QuerySet pickling to fail.
  98. """
  99. g = Group.objects.create(name='foo')
  100. m2m = M2MModel.objects.create()
  101. m2m.groups.add(g)
  102. Group.objects.all().delete()
  103. m2ms = M2MModel.objects.prefetch_related('groups')
  104. m2ms = pickle.loads(pickle.dumps(m2ms))
  105. self.assertQuerysetEqual(m2ms, [m2m], lambda x: x)
  106. def test_annotation_with_callable_default(self):
  107. # Happening.when has a callable default of datetime.datetime.now.
  108. qs = Happening.objects.annotate(latest_time=models.Max('when'))
  109. self.assert_pickles(qs)
  110. def test_missing_django_version_unpickling(self):
  111. """
  112. #21430 -- Verifies a warning is raised for querysets that are
  113. unpickled without a Django version
  114. """
  115. qs = Group.missing_django_version_objects.all()
  116. msg = "Pickled queryset instance's Django version is not specified."
  117. with self.assertRaisesMessage(RuntimeWarning, msg):
  118. pickle.loads(pickle.dumps(qs))
  119. def test_unsupported_unpickle(self):
  120. """
  121. #21430 -- Verifies a warning is raised for querysets that are
  122. unpickled with a different Django version than the current
  123. """
  124. qs = Group.previous_django_version_objects.all()
  125. msg = "Pickled queryset instance's Django version 1.0 does not match the current version %s." % get_version()
  126. with self.assertRaisesMessage(RuntimeWarning, msg):
  127. pickle.loads(pickle.dumps(qs))