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

File 5722-newforms-file-imagefield.diff, 8.8 KB (added by stefan+django@…, 12 years ago)

patch against current trunk

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

     
    734734            else:
    735735                func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save)
    736736
     737    def formfield_save_file(self, field_name, new_data, new_object, save=True):
     738        if new_data[field_name]:
     739            func = getattr(new_object, 'save_%s_file' % self.name)
     740            func(new_data[field_name]["filename"], new_data[field_name]["content"], save)
     741
    737742    def get_directory_name(self):
    738743        return os.path.normpath(force_unicode(datetime.datetime.now().strftime(smart_str(self.upload_to))))
    739744
     
    742747        f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename)))
    743748        return os.path.normpath(f)
    744749
     750    def formfield(self, **kwargs):
     751        defaults = {'form_class': forms.FileField}
     752        defaults.update(kwargs)
     753        return super(FileField, self).formfield(**defaults)
     754
    745755class FilePathField(Field):
    746756    def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs):
    747757        self.path, self.match, self.recursive = path, match, recursive
     
    790800                setattr(new_object, self.height_field, getattr(original_object, self.height_field))
    791801            new_object.save()
    792802
     803    def formfield(self, **kwargs):
     804        defaults = {'form_class': forms.ImageField}
     805        defaults.update(kwargs)
     806        return super(ImageField, self).formfield(**defaults)
     807
    793808class IntegerField(Field):
    794809    empty_strings_allowed = False
    795810    def get_manipulator_field_objs(self):
  • django/newforms/models.py

     
    3232    for f in opts.fields:
    3333        if not f.editable or isinstance(f, models.AutoField) or not f.name in cleaned_data:
    3434            continue
     35        if isinstance(f, models.FileField):
     36            continue
    3537        if fields and f.name not in fields:
    3638            continue
    3739        setattr(instance, f.name, cleaned_data[f.name])
     40
     41    # FileField may need more info to save to specific paths
     42    for f in opts.fields:
     43        if isinstance(f, models.FileField) and cleaned_data.has_key(f.name):
     44            f.formfield_save_file(f.name, cleaned_data, instance, save=False)
     45
    3846    if commit:
    3947        instance.save()
    4048        for f in opts.many_to_many:
     
    95103    takes a database Field instance, plus **kwargs, and returns a form Field
    96104    instance with the given kwargs (i.e. 'initial').
    97105    """
     106    from django.db import models
    98107    model = instance.__class__
    99108    opts = model._meta
    100109    field_list = []
     
    106115        current_value = f.value_from_object(instance)
    107116        formfield = formfield_callback(f, initial=current_value)
    108117        if formfield:
     118            # FileFields are only required once, because we cannot print the
     119            # existing data into the <form>
     120            if isinstance(f, models.FileField) and current_value:
     121                formfield.required = False
    109122            field_list.append((f.name, formfield))
    110123    base_fields = SortedDictFromList(field_list)
    111124    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
    1515try:
    1616    from decimal import Decimal, DecimalException
     
    1818    from django.utils._decimal import Decimal, DecimalException
    1919
    2020__all__ = (
    21     'Field', 'CharField', 'IntegerField',
     21    'Field', 'CharField', 'FileField', 'ImageField', 'IntegerField',
    2222    'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
    2323    'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
    2424    'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
     
    122122        if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
    123123            return {'maxlength': str(self.max_length)}
    124124
     125class FileField(Field):
     126    widget = FileInput
     127   
     128    def clean(self, value):
     129        super(FileField, self).clean(value)
     130        if value in EMPTY_VALUES:
     131            return None
     132        else:
     133            try:
     134                content = value['content']
     135            except TypeError:
     136                raise ValidationError(gettext("No file was submitted. Check the encoding type on the form."))
     137            if not content:
     138                raise ValidationError(gettext(u'The submitted file is empty.'))
     139            return value
     140
     141class ImageField(FileField):
     142    def clean(self, value):
     143        super(ImageField, self).clean(value)
     144        if value in EMPTY_VALUES:
     145            return None
     146        else:
     147            from PIL import Image
     148            from cStringIO import StringIO
     149            try:
     150                Image.open(StringIO(value['content']))
     151            except IOError: # Python Imaging Library doesn't recognize it as an image
     152                raise ValidationError, gettext(u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.')
     153            return value
     154
    125155class IntegerField(Field):
    126156    def __init__(self, max_value=None, min_value=None, *args, **kwargs):
    127157        self.max_value, self.min_value = max_value, min_value
  • tests/modeltests/model_forms/models.py

     
    6868    def __unicode__(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