Ticket #3297: 4549-with-more-tests-and-imagefield.patch

File 4549-with-more-tests-and-imagefield.patch, 11.4 KB (added by Øyvind Saltvik <oyvind@…>, 12 years ago)

Added one more validator, fixed formfield_save_file, and better tests

  • django/db/models/fields/__init__.py

     
    658658            else:
    659659                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"])
    660660
     661    def formfield_save_file(self, field_name, new_data, new_object):
     662        if new_data[field_name][0]:
     663            func = getattr(new_object, 'save_%s_file' % self.name)
     664            func(new_data[field_name][0]["filename"], new_data[field_name][0]["content"])
     665
    661666    def get_directory_name(self):
    662667        return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
    663668
     
    666671        f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    667672        return os.path.normpath(f)
    668673
     674    def formfield(self, **kwargs):
     675        defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput}
     676        defaults.update(kwargs)
     677        return forms.FileField(**defaults)
     678
    669679class FilePathField(Field):
    670680    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    671681        self.path, self.match, self.recursive = path, match, recursive
     
    712722                setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    713723            new_object.save()
    714724
     725    def formfield(self, **kwargs):
     726        defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput}
     727        defaults.update(kwargs)
     728        return forms.ImageField(**defaults)
     729
    715730class IntegerField(Field):
    716731    empty_strings_allowed = False
    717732    def get_manipulator_field_objs(self):
  • django/newforms/models.py

     
    1616
    1717    This method is created for any form_for_model Form.
    1818    """
     19    from django.db import models
    1920    if self.errors:
    2021        raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name)
    2122    return save_instance(self, self._model(), commit)
     
    3637    for f in opts.fields:
    3738        if not f.editable or isinstance(f, models.AutoField):
    3839            continue
     40        if isinstance(f,models.FileField):
     41            continue
    3942        setattr(instance, f.name, clean_data[f.name])
    4043    if commit:
    4144        instance.save()
    4245        for f in opts.many_to_many:
    4346            setattr(instance, f.attname, clean_data[f.name])
     47        for f in opts.fields:
     48            if isinstance(f, models.FileField):
     49                f.formfield_save_file(f.name, clean_data, instance)
    4450    # GOTCHA: If many-to-many data is given and commit=False, the many-to-many
    4551    # data will be lost. This happens because a many-to-many options cannot be
    4652    # set on an object until after it's saved. Maybe we should raise an
  • django/newforms/fields.py

     
    1010import time
    1111
    1212__all__ = (
    13     'Field', 'CharField', 'IntegerField',
     13    'Field', 'CharField', 'FileField', 'ImageField', 'IntegerField',
    1414    'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
    1515    'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
    1616    'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
     
    107107        if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
    108108            return {'maxlength': str(self.max_length)}
    109109
     110class FileField(Field):
     111
     112    prev_error = False
     113 
     114    def clean(self, value):
     115        super(FileField, self).clean(value)
     116
     117        if value[0]:
     118            try:
     119                content = value[0]['content']
     120            except TypeError:
     121                self.prev_error = True
     122                raise ValidationError(gettext("No file was submitted. Check the encoding type on the form."))
     123
     124            if not content:
     125                self.prev_error = True
     126                raise ValidationError(gettext(u'The submitted file is empty.'))
     127
     128        elif self.required:
     129            if not value[1]:
     130                self.prev_error = True
     131                raise ValidationError(gettext(u'This field is required.'))
     132
     133        return value
     134
     135class ImageField(FileField):
     136   
     137    def clean(self, value):
     138        super(ImageField, self).clean(value)
     139        if value[0] and not self.prev_error:
     140            from PIL import Image
     141            from cStringIO import StringIO
     142            try:
     143                Image.open(StringIO(value[0]['content']))
     144            except IOError: # Python Imaging Library doesn't recognize it as an image
     145                raise ValidationError, gettext(u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.')
     146        return value
     147
    110148class IntegerField(Field):
    111149    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    112150        self.max_value, self.min_value = max_value, min_value
  • django/newforms/widgets.py

     
    115115
    116116class FileInput(Input):
    117117    input_type = 'file'
     118   
     119    def render(self,name,value,attrs=None,choices=()):
     120        if value is None: value = ''
     121        file_attrs = self.build_attrs(attrs, type='file', name=name+'_file')
     122        final_attrs = self.build_attrs(attrs, type='hidden', name=name)
     123        if value != '': final_attrs['value'] = smart_unicode(value) # only add the value attribute if a value is non-empty
     124       
     125        if value != '':
     126            currently = u'Currently: %s<br/>Change: ' % smart_unicode(value)
     127            current = u' <input%s />' % flatatt(final_attrs)
     128        else:
     129            currently = u''
     130            current = u''
     131         
     132        return u'%s<input%s />%s' % (currently,flatatt(file_attrs),current)
     133   
     134    def value_from_datadict(self,data,name):
     135        return [data.get(name+'_file',None),data.get(name,None)]
    118136
    119137class Textarea(Widget):
    120138    def render(self, name, value, attrs=None):
  • tests/modeltests/model_forms/models.py

     
    5454    def __str__(self):
    5555        return self.headline
    5656
     57class NotRequiredFile(models.Model):
     58    description = models.CharField(maxlength=50)
     59    file = models.FileField(upload_to='files', blank=True)
     60
     61    def __str__(self):
     62        return self.description
     63
     64class RequiredFile(models.Model):
     65    description = models.CharField(maxlength=50)
     66    file = models.FileField(upload_to='files')
     67
     68    def __str__(self):
     69        return self.description
     70
    5771__test__ = {'API_TESTS': """
    5872>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
    5973>>> import datetime
     
    370384Traceback (most recent call last):
    371385...
    372386ValidationError: [u'Select a valid choice. 5 is not one of the available choices.']
     387
     388Test for filefield
     389
     390>>> form_data = {'description': 'FileField test', 'file_file': {'content': 'FileField test', 'filename': 'filetest.txt'} }
     391>>> no_file_form_data = {'description': 'FileField test'}
     392>>> just_path_form_data = {'description': 'FileField test', 'file': 'files/filetest.txt'}
     393>>> bad_encoding_form_data = {'description': 'FileField test', 'file': 'files/filetest.txt', 'file_file': 'wrong encoding'}
     394>>> TestRequiredFileForm = form_for_model(RequiredFile)
     395>>> empty_required_fileform = TestRequiredFileForm(auto_id=False)
     396>>> print empty_required_fileform.as_ul()
     397<li>Description: <input type="text" name="description" maxlength="50" /></li>
     398<li>File: <input type="file" name="file_file" /></li>
     399
     400Test with data
     401>>> filled_required_fileform= TestRequiredFileForm(form_data, auto_id=False)
     402>>> filled_required_fileform.is_valid()
     403True
     404
     405>>> required_file_instance = filled_required_fileform.save()
     406>>> print required_file_instance.file
     407files/filetest.txt
     408>>> TestInstanceRequiredFileForm = form_for_instance(required_file_instance)
     409>>> instance_required_fileform = TestInstanceRequiredFileForm(auto_id=False)
     410>>> instance_required_fileform.as_ul()
     411u'<li>Description: <input type="text" name="description" value="FileField test" maxlength="50" /></li>\\n<li>File: Currently: files/filetest.txt<br/>Change: <input type="file" name="file_file" /> <input type="hidden" name="file" value="files/filetest.txt" /></li>'
     412>>> required_file_instance.delete()
     413
     414Bad data test
     415>>> filled_required_fileform=TestRequiredFileForm(no_file_form_data)
     416>>> filled_required_fileform.is_valid()
     417False
     418>>> print filled_required_fileform.errors
     419<ul class="errorlist"><li>file<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
     420>>> TestNotRequiredFileForm = form_for_model(NotRequiredFile)
     421>>> filled_not_required_fileform=TestNotRequiredFileForm(no_file_form_data)
     422>>> filled_not_required_fileform.is_valid()
     423True
     424>>> filled_not_required_fileform=TestNotRequiredFileForm(bad_encoding_form_data)
     425>>> print filled_not_required_fileform.errors
     426<ul class="errorlist"><li>file<ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul></li></ul>
     427>>> filled_not_required_fileform=TestNotRequiredFileForm(just_path_form_data)
     428>>> filled_not_required_fileform.is_valid()
     429True
     430>>> filled_required_fileform=TestRequiredFileForm(just_path_form_data)
     431>>> filled_required_fileform.is_valid()
     432True
    373433"""}
  • tests/regressiontests/forms/tests.py

     
    165165# FileInput Widget ############################################################
    166166
    167167>>> w = FileInput()
    168 >>> w.render('email', '')
    169 u'<input type="file" name="email" />'
    170 >>> w.render('email', None)
    171 u'<input type="file" name="email" />'
    172 >>> w.render('email', 'test@example.com')
    173 u'<input type="file" name="email" value="test@example.com" />'
    174 >>> w.render('email', 'some "quoted" & ampersanded value')
    175 u'<input type="file" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
    176 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
    177 u'<input type="file" name="email" value="test@example.com" class="fun" />'
     168>>> w.render('file', '')
     169u'<input type="file" name="file_file" />'
     170>>> w.render('file', 'file/filetest.txt')
     171u'Currently: file/filetest.txt<br/>Change: <input type="file" name="file_file" /> <input type="hidden" name="file" value="file/filetest.txt" />'
    178172
    179 You can also pass 'attrs' to the constructor:
    180 >>> w = FileInput(attrs={'class': 'fun'})
    181 >>> w.render('email', '')
    182 u'<input type="file" class="fun" name="email" />'
    183 >>> w.render('email', 'foo@example.com')
    184 u'<input type="file" class="fun" value="foo@example.com" name="email" />'
    185 
    186 >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
    187 u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
    188 
    189173# Textarea Widget #############################################################
    190174
    191175>>> w = Textarea()
Back to Top