diff --git a/AUTHORS b/AUTHORS index 210f52c5a5..c89fd5ccac 100644 --- a/AUTHORS +++ b/AUTHORS @@ -35,6 +35,7 @@ answer newbie questions, and generally made Django that much better: Jeff Anderson Marian Andre Andreas + Victor Andrée andy@jadedplanet.net Fabrice Aneche ant9000@netwise.it diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index 878d09c976..f9bfc9d03f 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -132,7 +132,7 @@ class FileDescriptor(object): # have the FieldFile interface added to them file_copy = copy.copy(file) file_copy.__class__ = type(file.__class__.__name__, - (file.__class__, FieldFile), {}) + (file.__class__, self.field.attr_class), {}) file_copy.instance = instance file_copy.field = self.field file_copy.storage = self.field.storage diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 6ef44d909b..e12363cf3c 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -98,26 +98,47 @@ class TextFile(models.Model): def __unicode__(self): return self.description -class ImageFile(models.Model): - def custom_upload_path(self, filename): - path = self.path or 'tests' - return '%s/%s' % (path, filename) +try: + # If PIL is available, try testing ImageFields. + # Checking for the existence of Image is enough for CPython, but + # for PyPy, you need to check for the underlying modules + # If PIL is not available, ImageField tests are omitted. + from PIL import Image, _imaging + test_images = True - description = models.CharField(max_length=20) - try: - # If PIL is available, try testing PIL. - # Checking for the existence of Image is enough for CPython, but - # for PyPy, you need to check for the underlying modules - # If PIL is not available, this test is equivalent to TextFile above. - from PIL import Image, _imaging - image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path) - except ImportError: - image = models.FileField(storage=temp_storage, upload_to=custom_upload_path) - path = models.CharField(max_length=16, blank=True, default='') + class ImageFile(models.Model): + def custom_upload_path(self, filename): + path = self.path or 'tests' + return '%s/%s' % (path, filename) + + description = models.CharField(max_length=20) + image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path, + width_field='width', height_field='height') + width = models.IntegerField(editable=False) + height = models.IntegerField(editable=False) + path = models.CharField(max_length=16, blank=True, default='') - def __unicode__(self): - return self.description + def __unicode__(self): + return self.description + + class OptionalImageFile(models.Model): + def custom_upload_path(self, filename): + path = self.path or 'tests' + return '%s/%s' % (path, filename) + + description = models.CharField(max_length=20) + image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path, + width_field='width', height_field='height', + blank=True, null=True) + width = models.IntegerField(editable=False, null=True) + height = models.IntegerField(editable=False, null=True) + path = models.CharField(max_length=16, blank=True, default='') + def __unicode__(self): + return self.description +except ImportError: + test_images = False + class CommaSeparatedInteger(models.Model): field = models.CommaSeparatedIntegerField(max_length=20) @@ -1056,7 +1077,10 @@ True # Delete the current file since this is not done by Django. >>> instance.file.delete() >>> instance.delete() +"""} +if test_images: + __test__['API_TESTS'] += """ # ImageField ################################################################### # ImageField and FileField are nearly identical, but they differ slighty when @@ -1068,6 +1092,7 @@ True ... model = ImageFile >>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png"), 'rb').read() +>>> image_data2 = open(os.path.join(os.path.dirname(__file__), "test2.png"), 'rb').read() >>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)}) >>> f.is_valid() @@ -1077,6 +1102,10 @@ True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test.png> +>>> instance.width +16 +>>> instance.height +16 # Delete the current file since this is not done by Django. >>> instance.image.delete() @@ -1089,8 +1118,12 @@ True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test.png> +>>> instance.width +16 +>>> instance.height +16 -# Edit an instance that already has the image defined in the model. This will not +# Edit an instance that already has the (required) image defined in the model. This will not # save the image again, but leave it exactly as it is. >>> f = ImageFileForm(data={'description': u'Look, it changed'}, instance=instance) @@ -1101,6 +1134,10 @@ True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test.png> +>>> instance.height +16 +>>> instance.width +16 # Delete the current image since this is not done by Django. @@ -1108,23 +1145,31 @@ True # Override the file by uploading a new one. ->>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)}, instance=instance) +>>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data2)}, instance=instance) >>> f.is_valid() True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test2.png> +>>> instance.height +32 +>>> instance.width +48 # Delete the current file since this is not done by Django. >>> instance.image.delete() >>> instance.delete() ->>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data)}) +>>> f = ImageFileForm(data={'description': u'Changed it'}, files={'image': SimpleUploadedFile('test2.png', image_data2)}) >>> f.is_valid() True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test2.png> +>>> instance.height +32 +>>> instance.width +48 # Delete the current file since this is not done by Django. >>> instance.image.delete() @@ -1132,31 +1177,58 @@ True # Test the non-required ImageField ->>> f = ImageFileForm(data={'description': u'Test'}) ->>> f.fields['image'].required = False +>>> class OptionalImageFileForm(ModelForm): +... class Meta: +... model = OptionalImageFile + +>>> f = OptionalImageFileForm(data={'description': u'Test'}) >>> f.is_valid() True >>> instance = f.save() >>> instance.image <...FieldFile: None> +>>> instance.width +>>> instance.height ->>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance) +>>> f = OptionalImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}, instance=instance) >>> f.is_valid() True >>> instance = f.save() >>> instance.image <...FieldFile: tests/test3.png> +>>> instance.width +16 +>>> instance.height +16 + +# Editing the instance without re-uploading the image should not affect the image or its width/height properties +>>> f = OptionalImageFileForm(data={'description': u'New Description'}, instance=instance) +>>> f.is_valid() +True +>>> instance = f.save() +>>> instance.description +u'New Description' +>>> instance.image +<...FieldFile: tests/test3.png> +>>> instance.width +16 +>>> instance.height +16 # Delete the current file since this is not done by Django. >>> instance.image.delete() >>> instance.delete() ->>> f = ImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test3.png', image_data)}) +>>> f = OptionalImageFileForm(data={'description': u'And a final one'}, files={'image': SimpleUploadedFile('test4.png', image_data2)}) >>> f.is_valid() True >>> instance = f.save() >>> instance.image -<...FieldFile: tests/test3.png> +<...FieldFile: tests/test4.png> +>>> instance.width +48 +>>> instance.height +32 >>> instance.delete() # Test callable upload_to behavior that's dependent on the value of another field in the model @@ -1167,6 +1239,9 @@ True >>> instance.image <...FieldFile: foo/test4.png> >>> instance.delete() +""" + +__test__['API_TESTS'] += """ # Media on a ModelForm ######################################################## @@ -1355,4 +1430,4 @@ ValidationError: [u'Select a valid choice. z is not one of the available choices # Clean up >>> import shutil >>> shutil.rmtree(temp_storage_dir) -"""} +""" diff --git a/tests/modeltests/model_forms/test2.png b/tests/modeltests/model_forms/test2.png new file mode 100644 index 0000000000..10702f75a1 Binary files /dev/null and b/tests/modeltests/model_forms/test2.png differ