summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMarc Garcia <garcia.marc@gmail.com>2009-06-07 00:30:56 +0000
committerMarc Garcia <garcia.marc@gmail.com>2009-06-07 00:30:56 +0000
commitf973c57aaac3e918ac0234acbbbc86834ccfca86 (patch)
treedcffd814d5881868ac72c01cabc220c4c4995ccb /tests
parent3860c69bad92e4a514b1d10426445a00f3e9239a (diff)
Merged up to trunk r10934
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/i18n-improvements@10935 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'tests')
-rw-r--r--tests/modeltests/defer/models.py92
-rw-r--r--tests/modeltests/model_forms/models.py21
-rw-r--r--tests/regressiontests/admin_scripts/tests.py2
-rw-r--r--tests/regressiontests/defer_regress/models.py22
-rw-r--r--tests/regressiontests/delete_regress/__init__.py1
-rw-r--r--tests/regressiontests/delete_regress/models.py61
-rw-r--r--tests/regressiontests/file_storage/models.py93
-rw-r--r--tests/regressiontests/file_storage/tests.py12
-rw-r--r--tests/regressiontests/model_fields/4x8.pngbin0 -> 87 bytes
-rw-r--r--tests/regressiontests/model_fields/8x4.pngbin0 -> 87 bytes
-rw-r--r--tests/regressiontests/model_fields/imagefield.py420
-rw-r--r--tests/regressiontests/model_fields/models.py107
-rw-r--r--tests/regressiontests/model_fields/tests.py16
-rw-r--r--tests/regressiontests/queries/models.py27
14 files changed, 758 insertions, 116 deletions
diff --git a/tests/modeltests/defer/models.py b/tests/modeltests/defer/models.py
index ce65065d40..96eb427811 100644
--- a/tests/modeltests/defer/models.py
+++ b/tests/modeltests/defer/models.py
@@ -17,6 +17,12 @@ class Primary(models.Model):
def __unicode__(self):
return self.name
+class Child(Primary):
+ pass
+
+class BigChild(Primary):
+ other = models.CharField(max_length=50)
+
def count_delayed_fields(obj, debug=False):
"""
Returns the number of delayed attributes on the given model instance.
@@ -33,7 +39,7 @@ def count_delayed_fields(obj, debug=False):
__test__ = {"API_TEST": """
To all outward appearances, instances with deferred fields look the same as
-normal instances when we examine attribut values. Therefore we test for the
+normal instances when we examine attribute values. Therefore we test for the
number of deferred fields on returned instances (by poking at the internals),
as a way to observe what is going on.
@@ -98,5 +104,89 @@ Using defer() and only() with get() is also valid.
>>> Primary.objects.all()
[<Primary: a new name>]
+# Regression for #10572 - A subclass with no extra fields can defer fields from the base class
+>>> _ = Child.objects.create(name="c1", value="foo", related=s1)
+
+# You can defer a field on a baseclass when the subclass has no fields
+>>> obj = Child.objects.defer("value").get(name="c1")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"c1"
+>>> obj.value
+u"foo"
+>>> obj.name = "c2"
+>>> obj.save()
+
+# You can retrive a single column on a base class with no fields
+>>> obj = Child.objects.only("name").get(name="c2")
+>>> count_delayed_fields(obj)
+3
+>>> obj.name
+u"c2"
+>>> obj.value
+u"foo"
+>>> obj.name = "cc"
+>>> obj.save()
+
+>>> _ = BigChild.objects.create(name="b1", value="foo", related=s1, other="bar")
+
+# You can defer a field on a baseclass
+>>> obj = BigChild.objects.defer("value").get(name="b1")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"b1"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b2"
+>>> obj.save()
+
+# You can defer a field on a subclass
+>>> obj = BigChild.objects.defer("other").get(name="b2")
+>>> count_delayed_fields(obj)
+1
+>>> obj.name
+u"b2"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b3"
+>>> obj.save()
+
+# You can retrieve a single field on a baseclass
+>>> obj = BigChild.objects.only("name").get(name="b3")
+>>> count_delayed_fields(obj)
+4
+>>> obj.name
+u"b3"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "b4"
+>>> obj.save()
+
+# You can retrieve a single field on a baseclass
+>>> obj = BigChild.objects.only("other").get(name="b4")
+>>> count_delayed_fields(obj)
+4
+>>> obj.name
+u"b4"
+>>> obj.value
+u"foo"
+>>> obj.other
+u"bar"
+>>> obj.name = "bb"
+>>> obj.save()
+
+# Finally, we need to flush the app cache for the defer module.
+# Using only/defer creates some artifical entries in the app cache
+# that messes up later tests. Purge all entries, just to be sure.
+>>> from django.db.models.loading import cache
+>>> cache.app_models['defer'] = {}
"""}
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 95fda273f0..0fd24c18ad 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -1175,8 +1175,9 @@ True
>>> instance.height
16
-# Delete the current file since this is not done by Django.
->>> instance.image.delete()
+# Delete the current file since this is not done by Django, but don't save
+# because the dimension fields are not null=True.
+>>> instance.image.delete(save=False)
>>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
>>> f.is_valid()
@@ -1207,9 +1208,9 @@ True
>>> instance.width
16
-# Delete the current image since this is not done by Django.
-
->>> instance.image.delete()
+# Delete the current file since this is not done by Django, but don't save
+# because the dimension fields are not null=True.
+>>> instance.image.delete(save=False)
# Override the file by uploading a new one.
@@ -1224,8 +1225,9 @@ True
>>> instance.width
48
-# Delete the current file since this is not done by Django.
->>> instance.image.delete()
+# Delete the current file since this is not done by Django, but don't save
+# because the dimension fields are not null=True.
+>>> instance.image.delete(save=False)
>>> instance.delete()
>>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data2)})
@@ -1239,8 +1241,9 @@ True
>>> instance.width
48
-# Delete the current file since this is not done by Django.
->>> instance.image.delete()
+# Delete the current file since this is not done by Django, but don't save
+# because the dimension fields are not null=True.
+>>> instance.image.delete(save=False)
>>> instance.delete()
# Test the non-required ImageField
diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
index 0e28a9749f..e67126e9a7 100644
--- a/tests/regressiontests/admin_scripts/tests.py
+++ b/tests/regressiontests/admin_scripts/tests.py
@@ -536,7 +536,7 @@ class DjangoAdminSettingsDirectory(AdminScriptTestCase):
args = ['startapp','settings_test']
out, err = self.run_django_admin(args,'settings')
self.assertNoOutput(err)
- self.assertTrue(os.path.exists(os.path.join(test_dir, 'settings_test')))
+ self.assert_(os.path.exists(os.path.join(test_dir, 'settings_test')))
shutil.rmtree(os.path.join(test_dir, 'settings_test'))
def test_builtin_command(self):
diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py
index 11ce1557fe..da9822ab88 100644
--- a/tests/regressiontests/defer_regress/models.py
+++ b/tests/regressiontests/defer_regress/models.py
@@ -84,7 +84,8 @@ Some further checks for select_related() and inherited model behaviour
(regression for #10710).
>>> c1 = Child.objects.create(name="c1", value=42)
->>> obj = Leaf.objects.create(name="l1", child=c1)
+>>> c2 = Child.objects.create(name="c2", value=37)
+>>> obj = Leaf.objects.create(name="l1", child=c1, second_child=c2)
>>> obj = Leaf.objects.only("name", "child").select_related()[0]
>>> obj.child.name
@@ -101,5 +102,24 @@ types as their non-deferred versions (bug #10738).
>>> c1 is c2 is c3
True
+# Regression for #10733 - only() can be used on a model with two foreign keys.
+>>> results = Leaf.objects.all().only('name', 'child', 'second_child').select_related()
+>>> results[0].child.name
+u'c1'
+>>> results[0].second_child.name
+u'c2'
+
+>>> results = Leaf.objects.all().only('name', 'child', 'second_child', 'child__name', 'second_child__name').select_related()
+>>> results[0].child.name
+u'c1'
+>>> results[0].second_child.name
+u'c2'
+
+# Finally, we need to flush the app cache for the defer module.
+# Using only/defer creates some artifical entries in the app cache
+# that messes up later tests. Purge all entries, just to be sure.
+>>> from django.db.models.loading import cache
+>>> cache.app_models['defer_regress'] = {}
+
"""
}
diff --git a/tests/regressiontests/delete_regress/__init__.py b/tests/regressiontests/delete_regress/__init__.py
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/tests/regressiontests/delete_regress/__init__.py
@@ -0,0 +1 @@
+
diff --git a/tests/regressiontests/delete_regress/models.py b/tests/regressiontests/delete_regress/models.py
new file mode 100644
index 0000000000..93cadc58fa
--- /dev/null
+++ b/tests/regressiontests/delete_regress/models.py
@@ -0,0 +1,61 @@
+from django.conf import settings
+from django.db import models, backend, connection, transaction
+from django.db.models import sql, query
+from django.test import TransactionTestCase
+
+class Book(models.Model):
+ pagecount = models.IntegerField()
+
+# Can't run this test under SQLite, because you can't
+# get two connections to an in-memory database.
+if settings.DATABASE_ENGINE != 'sqlite3':
+ class DeleteLockingTest(TransactionTestCase):
+ def setUp(self):
+ # Create a second connection to the database
+ self.conn2 = backend.DatabaseWrapper({
+ 'DATABASE_HOST': settings.DATABASE_HOST,
+ 'DATABASE_NAME': settings.DATABASE_NAME,
+ 'DATABASE_OPTIONS': settings.DATABASE_OPTIONS,
+ 'DATABASE_PASSWORD': settings.DATABASE_PASSWORD,
+ 'DATABASE_PORT': settings.DATABASE_PORT,
+ 'DATABASE_USER': settings.DATABASE_USER,
+ 'TIME_ZONE': settings.TIME_ZONE,
+ })
+
+ # Put both DB connections into managed transaction mode
+ transaction.enter_transaction_management()
+ transaction.managed(True)
+ self.conn2._enter_transaction_management(True)
+
+ def tearDown(self):
+ # Close down the second connection.
+ transaction.leave_transaction_management()
+ self.conn2.close()
+
+ def test_concurrent_delete(self):
+ "Deletes on concurrent transactions don't collide and lock the database. Regression for #9479"
+
+ # Create some dummy data
+ b1 = Book(id=1, pagecount=100)
+ b2 = Book(id=2, pagecount=200)
+ b3 = Book(id=3, pagecount=300)
+ b1.save()
+ b2.save()
+ b3.save()
+
+ transaction.commit()
+
+ self.assertEquals(3, Book.objects.count())
+
+ # Delete something using connection 2.
+ cursor2 = self.conn2.cursor()
+ cursor2.execute('DELETE from delete_regress_book WHERE id=1')
+ self.conn2._commit();
+
+ # Now perform a queryset delete that covers the object
+ # deleted in connection 2. This causes an infinite loop
+ # under MySQL InnoDB unless we keep track of already
+ # deleted objects.
+ Book.objects.filter(pagecount__lt=250).delete()
+ transaction.commit()
+ self.assertEquals(1, Book.objects.count())
diff --git a/tests/regressiontests/file_storage/models.py b/tests/regressiontests/file_storage/models.py
index 32af5d7588..e69de29bb2 100644
--- a/tests/regressiontests/file_storage/models.py
+++ b/tests/regressiontests/file_storage/models.py
@@ -1,93 +0,0 @@
-import os
-import tempfile
-import shutil
-from django.db import models
-from django.core.files.storage import FileSystemStorage
-from django.core.files.base import ContentFile
-
-# Test for correct behavior of width_field/height_field.
-# Of course, we can't run this without PIL.
-
-try:
- # Checking for the existence of Image is enough for CPython, but
- # for PyPy, you need to check for the underlying modules
- from PIL import Image, _imaging
-except ImportError:
- Image = None
-
-# If we have PIL, do these tests
-if Image:
- temp_storage_dir = tempfile.mkdtemp()
- temp_storage = FileSystemStorage(temp_storage_dir)
-
- class Person(models.Model):
- name = models.CharField(max_length=50)
- mugshot = models.ImageField(storage=temp_storage, upload_to='tests',
- height_field='mug_height',
- width_field='mug_width')
- mug_height = models.PositiveSmallIntegerField()
- mug_width = models.PositiveSmallIntegerField()
-
- __test__ = {'API_TESTS': """
->>> from django.core.files import File
->>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png"), 'rb').read()
->>> p = Person(name="Joe")
->>> p.mugshot.save("mug", ContentFile(image_data))
->>> p.mugshot.width
-16
->>> p.mugshot.height
-16
->>> p.mug_height
-16
->>> p.mug_width
-16
-
-# Bug #9786: Ensure '==' and '!=' work correctly.
->>> image_data = open(os.path.join(os.path.dirname(__file__), "test1.png"), 'rb').read()
->>> p1 = Person(name="Bob")
->>> p1.mugshot.save("mug", ContentFile(image_data))
->>> p2 = Person.objects.get(name="Joe")
->>> p.mugshot == p2.mugshot
-True
->>> p.mugshot != p2.mugshot
-False
->>> p.mugshot != p1.mugshot
-True
-
-Bug #9508: Similarly to the previous test, make sure hash() works as expected
-(equal items must hash to the same value).
->>> hash(p.mugshot) == hash(p2.mugshot)
-True
-
-# Bug #8175: correctly delete files that have been removed off the file system.
->>> import os
->>> p2 = Person(name="Fred")
->>> p2.mugshot.save("shot", ContentFile(image_data))
->>> os.remove(p2.mugshot.path)
->>> p2.delete()
-
-# Bug #8534: FileField.size should not leave the file open.
->>> p3 = Person(name="Joan")
->>> p3.mugshot.save("shot", ContentFile(image_data))
-
-# Get a "clean" model instance
->>> p3 = Person.objects.get(name="Joan")
-
-# It won't have an opened file.
->>> p3.mugshot.closed
-True
-
-# After asking for the size, the file should still be closed.
->>> _ = p3.mugshot.size
->>> p3.mugshot.closed
-True
-
-# Make sure that wrapping the file in a file still works
->>> p3.mugshot.file.open()
->>> p = Person.objects.create(name="Bob The Builder", mugshot=File(p3.mugshot.file))
->>> p.save()
->>> p3.mugshot.file.close()
-
-# Delete all test files
->>> shutil.rmtree(temp_storage_dir)
-"""}
diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py
index 6e2b7be8e7..c228764e06 100644
--- a/tests/regressiontests/file_storage/tests.py
+++ b/tests/regressiontests/file_storage/tests.py
@@ -161,9 +161,9 @@ class FileStoragePathParsing(TestCase):
self.storage.save('dotted.path/test', ContentFile("1"))
self.storage.save('dotted.path/test', ContentFile("2"))
- self.assertFalse(os.path.exists(os.path.join(self.storage_dir, 'dotted_.path')))
- self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test')))
- self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test_')))
+ self.failIf(os.path.exists(os.path.join(self.storage_dir, 'dotted_.path')))
+ self.assert_(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test')))
+ self.assert_(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test_')))
def test_first_character_dot(self):
"""
@@ -173,13 +173,13 @@ class FileStoragePathParsing(TestCase):
self.storage.save('dotted.path/.test', ContentFile("1"))
self.storage.save('dotted.path/.test', ContentFile("2"))
- self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
+ self.assert_(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
# Before 2.6, a leading dot was treated as an extension, and so
# underscore gets added to beginning instead of end.
if sys.version_info < (2, 6):
- self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/_.test')))
+ self.assert_(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/_.test')))
else:
- self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_')))
+ self.assert_(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_')))
if Image is not None:
class DimensionClosingBug(TestCase):
diff --git a/tests/regressiontests/model_fields/4x8.png b/tests/regressiontests/model_fields/4x8.png
new file mode 100644
index 0000000000..ffce444d48
--- /dev/null
+++ b/tests/regressiontests/model_fields/4x8.png
Binary files differ
diff --git a/tests/regressiontests/model_fields/8x4.png b/tests/regressiontests/model_fields/8x4.png
new file mode 100644
index 0000000000..60e6d69ee1
--- /dev/null
+++ b/tests/regressiontests/model_fields/8x4.png
Binary files differ
diff --git a/tests/regressiontests/model_fields/imagefield.py b/tests/regressiontests/model_fields/imagefield.py
new file mode 100644
index 0000000000..dd79e7aefa
--- /dev/null
+++ b/tests/regressiontests/model_fields/imagefield.py
@@ -0,0 +1,420 @@
+import os
+import shutil
+
+from django.core.files import File
+from django.core.files.base import ContentFile
+from django.core.files.images import ImageFile
+from django.test import TestCase
+
+from models import Image, Person, PersonWithHeight, PersonWithHeightAndWidth, \
+ PersonDimensionsFirst, PersonTwoImages, TestImageFieldFile
+
+
+# If PIL available, do these tests.
+if Image:
+
+ from models import temp_storage_dir
+
+
+ class ImageFieldTestMixin(object):
+ """
+ Mixin class to provide common functionality to ImageField test classes.
+ """
+
+ # Person model to use for tests.
+ PersonModel = PersonWithHeightAndWidth
+ # File class to use for file instances.
+ File = ImageFile
+
+ def setUp(self):
+ """
+ Creates a pristine temp directory (or deletes and recreates if it
+ already exists) that the model uses as its storage directory.
+
+ Sets up two ImageFile instances for use in tests.
+ """
+ if os.path.exists(temp_storage_dir):
+ shutil.rmtree(temp_storage_dir)
+ os.mkdir(temp_storage_dir)
+
+ file_path1 = os.path.join(os.path.dirname(__file__), "4x8.png")
+ self.file1 = self.File(open(file_path1, 'rb'))
+
+ file_path2 = os.path.join(os.path.dirname(__file__), "8x4.png")
+ self.file2 = self.File(open(file_path2, 'rb'))
+
+ def tearDown(self):
+ """
+ Removes temp directory and all its contents.
+ """
+ shutil.rmtree(temp_storage_dir)
+
+ def check_dimensions(self, instance, width, height,
+ field_name='mugshot'):
+ """
+ Asserts that the given width and height values match both the
+ field's height and width attributes and the height and width fields
+ (if defined) the image field is caching to.
+
+ Note, this method will check for dimension fields named by adding
+ "_width" or "_height" to the name of the ImageField. So, the
+ models used in these tests must have their fields named
+ accordingly.
+
+ By default, we check the field named "mugshot", but this can be
+ specified by passing the field_name parameter.
+ """
+ field = getattr(instance, field_name)
+ # Check height/width attributes of field.
+ if width is None and height is None:
+ self.assertRaises(ValueError, getattr, field, 'width')
+ self.assertRaises(ValueError, getattr, field, 'height')
+ else:
+ self.assertEqual(field.width, width)
+ self.assertEqual(field.height, height)
+
+ # Check height/width fields of model, if defined.
+ width_field_name = field_name + '_width'
+ if hasattr(instance, width_field_name):
+ self.assertEqual(getattr(instance, width_field_name), width)
+ height_field_name = field_name + '_height'
+ if hasattr(instance, height_field_name):
+ self.assertEqual(getattr(instance, height_field_name), height)
+
+
+ class ImageFieldTests(ImageFieldTestMixin, TestCase):
+ """
+ Tests for ImageField that don't need to be run with each of the
+ different test model classes.
+ """
+
+ def test_equal_notequal_hash(self):
+ """
+ Bug #9786: Ensure '==' and '!=' work correctly.
+ Bug #9508: make sure hash() works as expected (equal items must
+ hash to the same value).
+ """
+ # Create two Persons with different mugshots.
+ p1 = self.PersonModel(name="Joe")
+ p1.mugshot.save("mug", self.file1)
+ p2 = self.PersonModel(name="Bob")
+ p2.mugshot.save("mug", self.file2)
+ self.assertEqual(p1.mugshot == p2.mugshot, False)
+ self.assertEqual(p1.mugshot != p2.mugshot, True)
+
+ # Test again with an instance fetched from the db.
+ p1_db = self.PersonModel.objects.get(name="Joe")
+ self.assertEqual(p1_db.mugshot == p2.mugshot, False)
+ self.assertEqual(p1_db.mugshot != p2.mugshot, True)
+
+ # Instance from db should match the local instance.
+ self.assertEqual(p1_db.mugshot == p1.mugshot, True)
+ self.assertEqual(hash(p1_db.mugshot), hash(p1.mugshot))
+ self.assertEqual(p1_db.mugshot != p1.mugshot, False)
+
+ def test_instantiate_missing(self):
+ """
+ If the underlying file is unavailable, still create instantiate the
+ object without error.
+ """
+ p = self.PersonModel(name="Joan")
+ p.mugshot.save("shot", self.file1)
+ p = self.PersonModel.objects.get(name="Joan")
+ path = p.mugshot.path
+ shutil.move(path, path + '.moved')
+ p2 = self.PersonModel.objects.get(name="Joan")
+
+ def test_delete_when_missing(self):
+ """
+ Bug #8175: correctly delete an object where the file no longer
+ exists on the file system.
+ """
+ p = self.PersonModel(name="Fred")
+ p.mugshot.save("shot", self.file1)
+ os.remove(p.mugshot.path)
+ p.delete()
+
+ def test_size_method(self):
+ """
+ Bug #8534: FileField.size should not leave the file open.
+ """
+ p = self.PersonModel(name="Joan")
+ p.mugshot.save("shot", self.file1)
+
+ # Get a "clean" model instance
+ p = self.PersonModel.objects.get(name="Joan")
+ # It won't have an opened file.
+ self.assertEqual(p.mugshot.closed, True)
+
+ # After asking for the size, the file should still be closed.
+ _ = p.mugshot.size
+ self.assertEqual(p.mugshot.closed, True)
+
+ def test_pickle(self):
+ """
+ Tests that ImageField can be pickled, unpickled, and that the
+ image of the unpickled version is the same as the original.
+ """
+ import pickle
+
+ p = Person(name="Joe")
+ p.mugshot.save("mug", self.file1)
+ dump = pickle.dumps(p)
+
+ p2 = Person(name="Bob")
+ p2.mugshot = self.file1
+
+ loaded_p = pickle.loads(dump)
+ self.assertEqual(p.mugshot, loaded_p.mugshot)
+
+
+ class ImageFieldTwoDimensionsTests(ImageFieldTestMixin, TestCase):
+ """
+ Tests behavior of an ImageField and its dimensions fields.
+ """
+
+ def test_constructor(self):
+ """
+ Tests assigning an image field through the model's constructor.
+ """
+ p = self.PersonModel(name='Joe', mugshot=self.file1)
+ self.check_dimensions(p, 4, 8)
+ p.save()
+ self.check_dimensions(p, 4, 8)
+
+ def test_image_after_constructor(self):
+ """
+ Tests behavior when image is not passed in constructor.
+ """
+ p = self.PersonModel(name='Joe')
+ # TestImageField value will default to being an instance of its
+ # attr_class, a TestImageFieldFile, with name == None, which will
+ # cause it to evaluate as False.
+ self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
+ self.assertEqual(bool(p.mugshot), False)
+
+ # Test setting a fresh created model instance.
+ p = self.PersonModel(name='Joe')
+ p.mugshot = self.file1
+ self.check_dimensions(p, 4, 8)
+
+ def test_create(self):
+ """
+ Tests assigning an image in Manager.create().
+ """
+ p = self.PersonModel.objects.create(name='Joe', mugshot=self.file1)
+ self.check_dimensions(p, 4, 8)
+
+ def test_default_value(self):
+ """
+ Tests that the default value for an ImageField is an instance of
+ the field's attr_class (TestImageFieldFile in this case) with no
+ name (name set to None).
+ """
+ p = self.PersonModel()
+ self.assertEqual(isinstance(p.mugshot, TestImageFieldFile), True)
+ self.assertEqual(bool(p.mugshot), False)
+
+ def test_assignment_to_None(self):
+ """
+ Tests that assigning ImageField to None clears dimensions.
+ """
+ p = self.PersonModel(name='Joe', mugshot=self.file1)
+ self.check_dimensions(p, 4, 8)
+
+ # If image assigned to None, dimension fields should be cleared.
+ p.mugshot = None
+ self.check_dimensions(p, None, None)
+
+ p.mugshot = self.file2
+ self.check_dimensions(p, 8, 4)
+
+ def test_field_save_and_delete_methods(self):
+ """
+ Tests assignment using the field's save method and deletion using
+ the field's delete method.
+ """
+ p = self.PersonModel(name='Joe')
+ p.mugshot.save("mug", self.file1)
+ self.check_dimensions(p, 4, 8)
+
+ # A new file should update dimensions.
+ p.mugshot.save("mug", self.file2)
+ self.check_dimensions(p, 8, 4)
+
+ # Field and dimensions should be cleared after a delete.
+ p.mugshot.delete(save=False)
+ self.assertEqual(p.mugshot, None)
+ self.check_dimensions(p, None, None)
+
+ def test_dimensions(self):
+ """
+ Checks that dimensions are updated correctly in various situations.
+ """
+ p = self.PersonModel(name='Joe')
+
+ # Dimensions should get set if file is saved.
+ p.mugshot.save("mug", self.file1)
+ self.check_dimensions(p, 4, 8)
+
+ # Test dimensions after fetching from database.
+ p = self.PersonModel.objects.get(name='Joe')
+ # Bug 11084: Dimensions should not get recalculated if file is
+ # coming from the database. We test this by checking if the file
+ # was opened.
+ self.assertEqual(p.mugshot.was_opened, False)
+ self.check_dimensions(p, 4, 8)
+ # After checking dimensions on the image field, the file will have
+ # opened.
+ self.assertEqual(p.mugshot.was_opened, True)
+ # Dimensions should now be cached, and if we reset was_opened and
+ # check dimensions again, the file should not have opened.
+ p.mugshot.was_opened = False
+ self.check_dimensions(p, 4, 8)
+ self.assertEqual(p.mugshot.was_opened, False)
+
+ # If we assign a new image to the instance, the dimensions should
+ # update.
+ p.mugshot = self.file2
+ self.check_dimensions(p, 8, 4)
+ # Dimensions were recalculated, and hence file should have opened.
+ self.assertEqual(p.mugshot.was_opened, True)
+
+
+ class ImageFieldNoDimensionsTests(ImageFieldTwoDimensionsTests):
+ """
+ Tests behavior of an ImageField with no dimension fields.
+ """
+
+ PersonModel = Person
+
+
+ class ImageFieldOneDimensionTests(ImageFieldTwoDimensionsTests):
+ """
+ Tests behavior of an ImageField with one dimensions field.
+ """
+
+ PersonModel = PersonWithHeight
+
+
+ class ImageFieldDimensionsFirstTests(ImageFieldTwoDimensionsTests):
+ """
+ Tests behavior of an ImageField where the dimensions fields are
+ defined before the ImageField.
+ """
+
+ PersonModel = PersonDimensionsFirst
+
+
+ class ImageFieldUsingFileTests(ImageFieldTwoDimensionsTests):
+ """
+ Tests behavior of an ImageField when assigning it a File instance
+ rather than an ImageFile instance.
+ """
+
+ PersonModel = PersonDimensionsFirst
+ File = File
+
+
+ class TwoImageFieldTests(ImageFieldTestMixin, TestCase):
+ """
+ Tests a model with two ImageFields.
+ """
+
+ PersonModel = PersonTwoImages
+
+ def test_constructor(self):
+ p = self.PersonModel(mugshot=self.file1, headshot=self.file2)
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+ p.save()
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+
+ def test_create(self):
+ p = self.PersonModel.objects.create(mugshot=self.file1,
+ headshot=self.file2)
+ self.check_dimensions(p, 4, 8)
+ self.check_dimensions(p, 8, 4, 'headshot')
+
+ def test_assignment(self):
+ p = self.PersonModel()
+ self.check_dimensions(p, None, None, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+
+ p.mugshot = self.file1
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+ p.headshot = self.file2
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+
+ # Clear the ImageFields one at a time.
+ p.mugshot = None
+ self.check_dimensions(p, None, None, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+ p.headshot = None
+ self.check_dimensions(p, None, None, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+
+ def test_field_save_and_delete_methods(self):
+ p = self.PersonModel(name='Joe')
+ p.mugshot.save("mug", self.file1)
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+ p.headshot.save("head", self.file2)
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+
+ # We can use save=True when deleting the image field with null=True
+ # dimension fields and the other field has an image.
+ p.headshot.delete(save=True)
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+ p.mugshot.delete(save=False)
+ self.check_dimensions(p, None, None, 'mugshot')
+ self.check_dimensions(p, None, None, 'headshot')
+
+ def test_dimensions(self):
+ """
+ Checks that dimensions are updated correctly in various situations.
+ """
+ p = self.PersonModel(name='Joe')
+
+ # Dimensions should get set for the saved file.
+ p.mugshot.save("mug", self.file1)
+ p.headshot.save("head", self.file2)
+ self.check_dimensions(p, 4, 8, 'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+
+ # Test dimensions after fetching from database.
+ p = self.PersonModel.objects.get(name='Joe')
+ # Bug 11084: Dimensions should not get recalculated if file is
+ # coming from the database. We test this by checking if the file
+ # was opened.
+ self.assertEqual(p.mugshot.was_opened, False)
+ self.assertEqual(p.headshot.was_opened, False)
+ self.check_dimensions(p, 4, 8,'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+ # After checking dimensions on the image fields, the files will
+ # have been opened.
+ self.assertEqual(p.mugshot.was_opened, True)
+ self.assertEqual(p.headshot.was_opened, True)
+ # Dimensions should now be cached, and if we reset was_opened and
+ # check dimensions again, the file should not have opened.
+ p.mugshot.was_opened = False
+ p.headshot.was_opened = False
+ self.check_dimensions(p, 4, 8,'mugshot')
+ self.check_dimensions(p, 8, 4, 'headshot')
+ self.assertEqual(p.mugshot.was_opened, False)
+ self.assertEqual(p.headshot.was_opened, False)
+
+ # If we assign a new image to the instance, the dimensions should
+ # update.
+ p.mugshot = self.file2
+ p.headshot = self.file1
+ self.check_dimensions(p, 8, 4, 'mugshot')
+ self.check_dimensions(p, 4, 8, 'headshot')
+ # Dimensions were recalculated, and hence file should have opened.
+ self.assertEqual(p.mugshot.was_opened, True)
+ self.assertEqual(p.headshot.was_opened, True)
diff --git a/tests/regressiontests/model_fields/models.py b/tests/regressiontests/model_fields/models.py
index 43ef667d00..81e6c22f09 100644
--- a/tests/regressiontests/model_fields/models.py
+++ b/tests/regressiontests/model_fields/models.py
@@ -1,10 +1,23 @@
-from django.db import models
+import os
+import tempfile
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal # Python 2.3 fallback
+try:
+ # Checking for the existence of Image is enough for CPython, but for PyPy,
+ # you need to check for the underlying modules.
+ from PIL import Image, _imaging
+except ImportError:
+ Image = None
+
+from django.core.files.storage import FileSystemStorage
+from django.db import models
+from django.db.models.fields.files import ImageFieldFile, ImageField
+
+
class Foo(models.Model):
a = models.CharField(max_length=10)
d = models.DecimalField(max_digits=5, decimal_places=3)
@@ -31,9 +44,97 @@ class Whiz(models.Model):
(0,'Other'),
)
c = models.IntegerField(choices=CHOICES, null=True)
-
+
class BigD(models.Model):
d = models.DecimalField(max_digits=38, decimal_places=30)
class BigS(models.Model):
- s = models.SlugField(max_length=255) \ No newline at end of file
+ s = models.SlugField(max_length=255)
+
+
+###############################################################################
+# ImageField
+
+# If PIL available, do these tests.
+if Image:
+ class TestImageFieldFile(ImageFieldFile):
+ """
+ Custom Field File class that records whether or not the underlying file
+ was opened.
+ """
+ def __init__(self, *args, **kwargs):
+ self.was_opened = False
+ super(TestImageFieldFile, self).__init__(*args,**kwargs)
+ def open(self):
+ self.was_opened = True
+ super(TestImageFieldFile, self).open()
+
+ class TestImageField(ImageField):
+ attr_class = TestImageFieldFile
+
+ # Set up a temp directory for file storage.
+ temp_storage_dir = tempfile.mkdtemp()
+ temp_storage = FileSystemStorage(temp_storage_dir)
+ temp_upload_to_dir = os.path.join(temp_storage.location, 'tests')
+
+ class Person(models.Model):
+ """
+ Model that defines an ImageField with no dimension fields.
+ """
+ name = models.CharField(max_length=50)
+ mugshot = TestImageField(storage=temp_storage, upload_to='tests')
+
+ class PersonWithHeight(models.Model):
+ """
+ Model that defines an ImageField with only one dimension field.
+ """
+ name = models.CharField(max_length=50)
+ mugshot = TestImageField(storage=temp_storage, upload_to='tests',
+ height_field='mugshot_height')
+ mugshot_height = models.PositiveSmallIntegerField()
+
+ class PersonWithHeightAndWidth(models.Model):
+ """
+ Model that defines height and width fields after the ImageField.
+ """
+ name = models.CharField(max_length=50)
+ mugshot = TestImageField(storage=temp_storage, upload_to='tests',
+ height_field='mugshot_height',
+ width_field='mugshot_width')
+ mugshot_height = models.PositiveSmallIntegerField()
+ mugshot_width = models.PositiveSmallIntegerField()
+
+ class PersonDimensionsFirst(models.Model):
+ """
+ Model that defines height and width fields before the ImageField.
+ """
+ name = models.CharField(max_length=50)
+ mugshot_height = models.PositiveSmallIntegerField()
+ mugshot_width = models.PositiveSmallIntegerField()
+ mugshot = TestImageField(storage=temp_storage, upload_to='tests',
+ height_field='mugshot_height',
+ width_field='mugshot_width')
+
+ class PersonTwoImages(models.Model):
+ """
+ Model that:
+ * Defines two ImageFields
+ * Defines the height/width fields before the ImageFields
+ * Has a nullalble ImageField
+ """
+ name = models.CharField(max_length=50)
+ mugshot_height = models.PositiveSmallIntegerField()
+ mugshot_width = models.PositiveSmallIntegerField()
+ mugshot = TestImageField(storage=temp_storage, upload_to='tests',
+ height_field='mugshot_height',
+ width_field='mugshot_width')
+ headshot_height = models.PositiveSmallIntegerField(
+ blank=True, null=True)
+ headshot_width = models.PositiveSmallIntegerField(
+ blank=True, null=True)
+ headshot = TestImageField(blank=True, null=True,
+ storage=temp_storage, upload_to='tests',
+ height_field='headshot_height',
+ width_field='headshot_width')
+
+###############################################################################
diff --git a/tests/regressiontests/model_fields/tests.py b/tests/regressiontests/model_fields/tests.py
index 0815d9ef3c..7a6fee5a2a 100644
--- a/tests/regressiontests/model_fields/tests.py
+++ b/tests/regressiontests/model_fields/tests.py
@@ -6,13 +6,26 @@ from django import forms
from django.db import models
from django.core.exceptions import ValidationError
-from models import Foo, Bar, Whiz, BigD, BigS
+from models import Foo, Bar, Whiz, BigD, BigS, Image
try:
from decimal import Decimal
except ImportError:
from django.utils._decimal import Decimal
+
+# If PIL available, do these tests.
+if Image:
+ from imagefield import \
+ ImageFieldTests, \
+ ImageFieldTwoDimensionsTests, \
+ ImageFieldNoDimensionsTests, \
+ ImageFieldOneDimensionTests, \
+ ImageFieldDimensionsFirstTests, \
+ ImageFieldUsingFileTests, \
+ TwoImageFieldTests
+
+
class DecimalFieldTests(django.test.TestCase):
def test_to_python(self):
f = models.DecimalField(max_digits=4, decimal_places=2)
@@ -131,4 +144,3 @@ class SlugFieldTests(django.test.TestCase):
bs = BigS.objects.create(s = 'slug'*50)
bs = BigS.objects.get(pk=bs.pk)
self.assertEqual(bs.s, 'slug'*50)
-
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index b5fa377496..3649d27171 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -1143,6 +1143,33 @@ True
>>> r.save()
>>> Ranking.objects.all()
[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
+
+# Regression test for #10742:
+# Queries used in an __in clause don't execute subqueries
+
+>>> subq = Author.objects.filter(num__lt=3000)
+>>> qs = Author.objects.filter(pk__in=subq)
+>>> list(qs)
+[<Author: a1>, <Author: a2>]
+# The subquery result cache should not be populated
+>>> subq._result_cache is None
+True
+
+>>> subq = Author.objects.filter(num__lt=3000)
+>>> qs = Author.objects.exclude(pk__in=subq)
+>>> list(qs)
+[<Author: a3>, <Author: a4>]
+# The subquery result cache should not be populated
+>>> subq._result_cache is None
+True
+
+>>> subq = Author.objects.filter(num__lt=3000)
+>>> list(Author.objects.filter(Q(pk__in=subq) & Q(name='a1')))
+[<Author: a1>]
+# The subquery result cache should not be populated
+>>> subq._result_cache is None
+True
+
"""}
# In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__