Ticket #3297: 5268-newforms-file-imagefield.diff

File 5268-newforms-file-imagefield.diff, 8.6 KB (added by pterk@…, 12 years ago)

Diff against revision 5268.

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

     
    665665            else:
    666666                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
    667667
     668    def formfield_save_file(self, field_name, new_data, new_object, save=True):
     669        if new_data[field_name]:
     670            func = getattr(new_object, 'save_%s_file' % self.name)
     671            func(new_data[field_name]["filename"], new_data[field_name]["content"], save)
     672
    668673    def get_directory_name(self):
    669674        return os.path.normpath(datetime.datetime.now().strftime(self.upload_to))
    670675
     
    673678        f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    674679        return os.path.normpath(f)
    675680
     681    def formfield(self, **kwargs):
     682        defaults = {'form_class': forms.FileField}
     683        defaults.update(kwargs)
     684        return super(FileField, self).formfield(**defaults)
     685
    676686class FilePathField(Field):
    677687    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    678688        self.path, self.match, self.recursive = path, match, recursive
     
    719729                setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    720730            new_object.save()
    721731
     732    def formfield(self, **kwargs):
     733        defaults = {'form_class': forms.ImageField}
     734        defaults.update(kwargs)
     735        return super(ImageField, self).formfield(**defaults)
     736
    722737class IntegerField(Field):
    723738    empty_strings_allowed = False
    724739    def get_manipulator_field_objs(self):
  • django/newforms/models.py

     
    3131    for f in opts.fields:
    3232        if not f.editable or isinstance(f, models.AutoField) or not f.name in cleaned_data:
    3333            continue
     34        if isinstance(f, models.FileField):
     35            continue
    3436        if fields and f.name not in fields:
    3537            continue
    3638        setattr(instance, f.name, cleaned_data[f.name])
     39
     40    # FileField may need more info to save to specific paths
     41    for f in opts.fields:
     42        if isinstance(f, models.FileField) and cleaned_data.has_key(f.name):
     43            f.formfield_save_file(f.name, cleaned_data, instance, save=False)
     44
    3745    if commit:
    3846        instance.save()
    3947        for f in opts.many_to_many:
     
    94102    takes a database Field instance, plus **kwargs, and returns a form Field
    95103    instance with the given kwargs (i.e. 'initial').
    96104    """
     105    from django.db import models
    97106    model = instance.__class__
    98107    opts = model._meta
    99108    field_list = []
     
    105114        current_value = f.value_from_object(instance)
    106115        formfield = formfield_callback(f, initial=current_value)
    107116        if formfield:
     117            # FileFields are only required once, because we cannot print the
     118            # existing data into the <form>
     119            if isinstance(f, models.FileField) and current_value:
     120                formfield.required = False
    108121            field_list.append((f.name, formfield))
    109122    base_fields = SortedDictFromList(field_list)
    110123    return type(opts.object_name + 'InstanceForm', (form,),
  • django/newforms/fields.py

     
    1010from django.utils.encoding import smart_unicode
    1111
    1212from util import ErrorList, ValidationError
    13 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
     13from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, FileInput
    1414
    1515__all__ = (
    16     'Field', 'CharField', 'IntegerField',
     16    'Field', 'CharField', 'FileField', 'ImageField', 'IntegerField',
    1717    'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
    1818    'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
    1919    'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
     
    111111        if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
    112112            return {'maxlength': str(self.max_length)}
    113113
     114class FileField(Field):
     115    widget = FileInput
     116   
     117    def clean(self, value):
     118        super(FileField, self).clean(value)
     119        if value in EMPTY_VALUES:
     120            return None
     121        else:
     122            try:
     123                content = value['content']
     124            except TypeError:
     125                raise ValidationError(gettext("No file was submitted. Check the encoding type on the form."))
     126            if not content:
     127                raise ValidationError(gettext(u'The submitted file is empty.'))
     128            return value
     129
     130class ImageField(FileField):
     131    def clean(self, value):
     132        super(ImageField, self).clean(value)
     133        if value in EMPTY_VALUES:
     134            return None
     135        else:
     136            from PIL import Image
     137            from cStringIO import StringIO
     138            try:
     139                Image.open(StringIO(value['content']))
     140            except IOError: # Python Imaging Library doesn't recognize it as an image
     141                raise ValidationError, gettext(u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.')
     142            return value
     143
    114144class IntegerField(Field):
    115145    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    116146        self.max_value, self.min_value = max_value, min_value
  • tests/modeltests/model_forms/models.py

     
    6868    def __str__(self):
    6969        return self.phone
    7070
     71class NotRequiredFile(models.Model):
     72    description = models.CharField(maxlength=50)
     73    file = models.FileField(upload_to='files', blank=True)
     74
     75    def __str__(self):
     76        return self.description
     77
     78class RequiredFile(models.Model):
     79    description = models.CharField(maxlength=50)
     80    file = models.FileField(upload_to='files')
     81
     82    def __str__(self):
     83        return self.description
     84
    7185__test__ = {'API_TESTS': """
    7286>>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField
    7387>>> import datetime
     
    442456
    443457>>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False)
    444458>>> print f.clean('')
     459
     460Test for filefield
     461
     462>>> form_data = {'description': 'FileField test', 'file': {'content': 'FileField test', 'filename': 'filetest.txt'} }
     463>>> no_file_form_data = {'description': 'FileField test'}
     464>>> bad_encoding_form_data = {'description': 'FileField test', 'file': 'wrong encoding'}
     465>>> TestRequiredFileForm = form_for_model(RequiredFile)
     466>>> empty_required_fileform = TestRequiredFileForm(auto_id=False)
     467>>> print empty_required_fileform.as_ul()
     468<li>Description: <input type="text" name="description" maxlength="50" /></li>
     469<li>File: <input type="file" name="file" /></li>
     470
     471Test with data
     472>>> filled_required_fileform= TestRequiredFileForm(form_data, auto_id=False)
     473>>> filled_required_fileform.is_valid()
     474True
     475
     476>>> required_file_instance = filled_required_fileform.save()
     477>>> print required_file_instance.file
     478files/filetest.txt
     479>>> TestInstanceRequiredFileForm = form_for_instance(required_file_instance)
     480>>> instance_required_fileform = TestInstanceRequiredFileForm(auto_id=False)
     481>>> instance_required_fileform.as_ul()
     482u'<li>Description: <input type="text" name="description" value="FileField test" maxlength="50" /></li>\\n<li>File: <input type="file" name="file" /></li>'
     483>>> required_file_instance.delete()
     484
     485Bad data test
     486>>> filled_required_fileform=TestRequiredFileForm(no_file_form_data)
     487>>> filled_required_fileform.is_valid()
     488False
     489>>> print filled_required_fileform.errors
     490<ul class="errorlist"><li>file<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
     491>>> TestNotRequiredFileForm = form_for_model(NotRequiredFile)
     492>>> filled_not_required_fileform=TestNotRequiredFileForm(no_file_form_data)
     493>>> filled_not_required_fileform.is_valid()
     494True
     495>>> filled_not_required_fileform=TestNotRequiredFileForm(bad_encoding_form_data)
     496>>> print filled_not_required_fileform.errors
     497<ul class="errorlist"><li>file<ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul></li></ul>
    445498None
    446499>>> f.clean('')
    447500>>> f.clean('1')
Back to Top