Commits

Carl Meyer  committed 2f773b6

More backend-friendly image-detection in ImageWidget, no direct use of PIL. Fixes #7

  • Participants
  • Parent commits 86ab1a5

Comments (0)

Files changed (3)

 tip (unreleased)
 ----------------
 
+- Make ImageWidget image-detection backend-friendly, no direct use of
+  PIL. Fixes issue #7.
+
 - Fix default templates' rendering of labels for radio/checkbox inputs.
 
 - Fix error redisplaying bound form with ClearableFileField.
 
 0.1.8 (2010.03.16)
 ------------------
- 
+
 - Restrict PIL import to ImageWidget only
 
 - Added AutoResizeTextarea

File form_utils/widgets.py

         if template is not None:
             self.template = template
         super(ImageWidget, self).__init__(attrs)
-    
+
     def render(self, name, value, attrs=None):
-        from PIL import Image
         input_html = super(forms.FileInput, self).render(name, value, attrs)
-        file_name = str(value)
-        file_path = os.path.join(settings.MEDIA_ROOT, file_name)
-        try: # is image
-            Image.open(file_path)
-            image_html = thumbnail(str(value))
+        if hasattr(value, 'width') and hasattr(value, 'height'):
+            image_html = thumbnail(value.name)
             output = self.template % {'input': input_html,
                                       'image': image_html}
-        except IOError: # not image
+        else:
             output = input_html
         return mark_safe(output)
 
 class ClearableFileInput(forms.MultiWidget):
     default_file_widget_class = forms.FileInput
     template = '%(input)s Clear: %(checkbox)s'
-    
+
     def __init__(self, file_widget=None,
                  attrs=None, template=None):
         if template is not None:
         else:
             self.value = value
         return super(ClearableFileInput, self).render(name, value, attrs)
-        
+
     def decompress(self, value):
         # the clear checkbox is never initially checked
         return [value, None]
         return rendered_widgets[0]
 
 root = lambda path: posixpath.join(FORM_UTILS_MEDIA_URL, path)
-    
+
 class AutoResizeTextarea(forms.Textarea):
     """
     A Textarea widget that automatically resizes to accomodate its contents.
-    
+
     """
     class Media:
-        
+
         js = (JQUERY_URL,
               root('form_utils/js/jquery.autogrow.js'),
               root('form_utils/js/autoresize.js'))

File tests/tests.py

 from django import forms
 from django import template
 from django.core.files.uploadedfile import SimpleUploadedFile
+from django.db.models.fields.files import FieldFile, ImageFieldFile, FileField, ImageField
 from django.test import TestCase
 
 from form_utils.forms import BetterForm, BetterModelForm
     """
     A ``BetterModelForm`` whose fieldsets don't contain all fields
     from the model.
-    
+
     """
     class Meta:
         model = Person
     """
     A ``BetterModelForm`` whose fieldsets don't contain all fields
     from the model, but we set ``fields`` manually.
-    
+
     """
     class Meta:
         model = Person
         fieldsets = [('main', {'fields': ['name']})]
         fields = ['name', 'age']
-        
+
 class ExcludePartialPersonForm(BetterModelForm):
     """
     A ``BetterModelForm`` whose fieldsets don't contain all fields
     from the model, but we set ``exclude`` manually.
-    
+
     """
     class Meta:
         model = Person
         fieldsets = [('main', {'fields': ['name']})]
         exclude = ['age']
-        
+
 class AcrobaticPersonForm(PersonForm):
     """
     A ``BetterModelForm`` that inherits from another and overrides one
         fieldsets = fieldsets[:1] + \
                      [('Acrobatics', {'fields': ('age', 'speed', 'agility')})]
 
-                     
+
 class BetterFormTests(TestCase):
     fieldset_target_data = {
         ApplicationForm:
                                 }),
                     ],
         }
-        
+
     def test_iterate_fieldsets(self):
         """
         Test the definition and inheritance of fieldsets, by matching
                 # verify fieldset has correct attributes
                 for attr, val in target_data[1].items():
                     self.assertEquals(getattr(fs, attr), val)
-        
+
     def test_fieldset_errors(self):
         """
         We can access the ``errors`` attribute of a bound form and get
 class BoringForm(forms.Form):
     boredom = forms.IntegerField()
     excitement = forms.IntegerField()
-                          
+
 class TemplatetagTests(TestCase):
     boring_form_html = [
         u'<fieldset class="fieldset_main">',
         u'</ul>',
         u'</fieldset>',
         ]
-        
+
     def test_render_form(self):
         """
         A plain ``forms.Form`` renders as a list of fields.
 
         """
         widget = ImageWidget()
-        html = widget.render('fieldname', 'tiny.png')
+        html = widget.render('fieldname', ImageFieldFile(None, ImageField(), 'tiny.png'))
         # test only this much of the html, because the remainder will
         # vary depending on whether we have sorl-thumbnail
         self.failUnless(html.startswith(
                 '<input type="file" name="fieldname" value="tiny.png" />'
                 '<br /><img src="/media/tiny'))
 
+    def test_render_nonimage(self):
+        """
+        ``ImageWidget`` renders the file input only, if given a non-image.
+
+        """
+        widget = ImageWidget()
+        html = widget.render('fieldname', FieldFile(None, FileField(), 'something.txt'))
+        self.assertEquals(html, '<input type="file" name="fieldname" value="something.txt" />')
+
     def test_custom_template(self):
         """
         ``ImageWidget`` respects a custom template.
         """
         widget = ImageWidget(template='<div>%(image)s</div>'
                              '<div>%(input)s</div>')
-        html = widget.render('fieldname', 'tiny.png')
+        html = widget.render('fieldname', ImageFieldFile(None, ImageField(), 'tiny.png'))
         self.failUnless(html.startswith('<div><img src="/media/tiny'))
 
 
 
         """
         widget = ClearableFileInput(file_widget=ImageWidget())
-        html = widget.render('fieldname', 'tiny.png')
+        html = widget.render('fieldname', ImageFieldFile(None, ImageField(), 'tiny.png'))
         self.failUnless(html.startswith(
                 '<input type="file" name="fieldname_0" value="tiny.png" />'
                 '<br /><img src="/media/tiny'))
         class ClearableImageWidget(ClearableFileInput):
             default_file_widget_class = ImageWidget
         widget = ClearableImageWidget()
-        html = widget.render('fieldname', 'tiny.png')
+        html = widget.render('fieldname', ImageFieldFile(None, ImageField(), 'tiny.png'))
         self.failUnless(html.startswith(
                 '<input type="file" name="fieldname_0" value="tiny.png" />'
                 '<br /><img src="/media/tiny'))
 
         """
         widget = ClearableFileInput(template='Clear: %(checkbox)s %(input)s')
-        html = widget.render('fieldname', 'tiny.png')
+        html = widget.render('fieldname', ImageFieldFile(None, ImageField(), 'tiny.png'))
         self.assertEquals(html,
                           'Clear: '
                           '<input type="checkbox" name="fieldname_1" /> '
                           '<input type="file" name="fieldname_0" />')
-                          
+
     def test_custom_template_via_subclass(self):
         """
         Template can also be customized by subclassing.
                           'Clear: '
                           '<input type="checkbox" name="fieldname_1" /> '
                           '<input type="file" name="fieldname_0" />')
-                          
+
 
 class ClearableFileFieldTests(TestCase):
     upload = SimpleUploadedFile('something.txt', 'Something')
         self.assertEquals(unicode(form['f']),
                           u'<input type="file" name="f_0" id="id_f_0" />'
                           u' Clear: <input type="checkbox" name="f_1" id="id_f_1" />')
-    
+
     def test_not_cleared(self):
         """
         If the clear checkbox is not checked, the ``FileField`` data
             widget = ClearableImageWidget
         field = ClearableImageWidgetField()
         self.failUnless(isinstance(field.widget, ClearableImageWidget))
-
-