Ticket #3297: 4921-newforms-file-imagefield.diff
File 4921-newforms-file-imagefield.diff, 11.5 KB (added by , 18 years ago) |
---|
-
django/db/models/fields/__init__.py
==== Patch <django-newforms-file-imagefield> level 2 Source: 6666b74b-a72c-0410-9b74-dd6beae1e16f:/django/newforms-file-imagefield:5816 [local] Target: bcc190cf-cafb-0310-a4f2-bffc1f526a37:/django/trunk:4921 [mirrored] (http://code.djangoproject.com/svn/django/trunk) Log: r5600@damasonium: ddanier | 2007-03-27 16:06:05 +0200 * FileField and ImageField for newforms not using additional <input>'s r5808@damasonium: ddanier | 2007-04-04 10:08:34 +0200 * FileInput is now the default-widget for FileField === django/db/models/fields/__init__.py ==================================================================
663 663 else: 664 664 func(new_data[upload_field_name]["filename"], new_data[upload_field_name]["content"], save) 665 665 666 def formfield_save_file(self, field_name, new_data, new_object, save=True): 667 if new_data[field_name]: 668 func = getattr(new_object, 'save_%s_file' % self.name) 669 func(new_data[field_name]["filename"], new_data[field_name]["content"], save) 670 666 671 def get_directory_name(self): 667 672 return os.path.normpath(datetime.datetime.now().strftime(self.upload_to)) 668 673 … … 671 676 f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename))) 672 677 return os.path.normpath(f) 673 678 679 def formfield(self, **kwargs): 680 defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput} 681 defaults.update(kwargs) 682 return forms.FileField(**defaults) 683 674 684 class FilePathField(Field): 675 685 def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs): 676 686 self.path, self.match, self.recursive = path, match, recursive … … 717 727 setattr(new_object, self.height_field, getattr(original_object, self.height_field)) 718 728 new_object.save() 719 729 730 def formfield(self, **kwargs): 731 defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'widget': forms.FileInput} 732 defaults.update(kwargs) 733 return forms.ImageField(**defaults) 734 720 735 class IntegerField(Field): 721 736 empty_strings_allowed = False 722 737 def get_manipulator_field_objs(self): -
django/newforms/models.py
=== django/newforms/models.py ==================================================================
18 18 19 19 This method is created for any form_for_model Form. 20 20 """ 21 from django.db import models 21 22 if self.errors: 22 23 raise ValueError("The %s could not be created because the data didn't validate." % self._model._meta.object_name) 23 24 return save_instance(self, self._model(), commit) … … 36 37 raise ValueError("The %s could not be changed because the data didn't validate." % opts.object_name) 37 38 clean_data = form.clean_data 38 39 for f in opts.fields: 39 if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data: 40 continue 41 setattr(instance, f.name, clean_data[f.name]) 40 if clean_data.has_key(f.name): 41 if not f.editable or isinstance(f, models.AutoField): 42 continue 43 if isinstance(f, models.FileField): 44 continue 45 setattr(instance, f.name, clean_data[f.name]) 46 47 # FileField may need more info to save to specific paths 48 for f in opts.fields: 49 if isinstance(f, models.FileField) and clean_data.has_key(f.name): 50 f.formfield_save_file(f.name, clean_data, instance, save=False) 51 42 52 if commit: 43 53 instance.save() 44 54 for f in opts.many_to_many: … … 88 98 takes a database Field instance, plus **kwargs, and returns a form Field 89 99 instance with the given kwargs (i.e. 'initial'). 90 100 """ 101 from django.db import models 91 102 model = instance.__class__ 92 103 opts = model._meta 93 104 field_list = [] … … 97 108 current_value = f.value_from_object(instance) 98 109 formfield = formfield_callback(f, initial=current_value) 99 110 if formfield: 111 # FileFields are only required once, because we cannot print the 112 # existing data into the <form> 113 if isinstance(f, models.FileField) and current_value: 114 formfield.required = False 100 115 field_list.append((f.name, formfield)) 101 116 fields = SortedDictFromList(field_list) 102 117 return type(opts.object_name + 'InstanceForm', (form,), -
django/newforms/fields.py
=== django/newforms/fields.py ==================================================================
5 5 from django.utils.translation import gettext 6 6 from django.utils.encoding import smart_unicode 7 7 from util import ErrorList, ValidationError 8 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple 8 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, FileInput 9 9 import datetime 10 10 import re 11 11 import time 12 12 13 13 __all__ = ( 14 'Field', 'CharField', ' IntegerField',14 'Field', 'CharField', 'FileField', 'ImageField', 'IntegerField', 15 15 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', 16 16 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField', 17 17 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', … … 109 109 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): 110 110 return {'maxlength': str(self.max_length)} 111 111 112 class FileField(Field): 113 widget = FileInput 114 115 def clean(self, value): 116 super(FileField, self).clean(value) 117 if value in EMPTY_VALUES: 118 return None 119 else: 120 try: 121 content = value['content'] 122 except TypeError: 123 raise ValidationError(gettext("No file was submitted. Check the encoding type on the form.")) 124 if not content: 125 raise ValidationError(gettext(u'The submitted file is empty.')) 126 return value 127 128 class ImageField(FileField): 129 def clean(self, value): 130 super(ImageField, self).clean(value) 131 if value in EMPTY_VALUES: 132 return None 133 else: 134 from PIL import Image 135 from cStringIO import StringIO 136 try: 137 Image.open(StringIO(value['content'])) 138 except IOError: # Python Imaging Library doesn't recognize it as an image 139 raise ValidationError, gettext(u'Upload a valid image. The file you uploaded was either not an image or a corrupted image.') 140 return value 141 112 142 class IntegerField(Field): 113 143 def __init__(self, max_value=None, min_value=None, *args, **kwargs): 114 144 self.max_value, self.min_value = max_value, min_value -
tests/modeltests/model_forms/models.py
=== tests/modeltests/model_forms/models.py ==================================================================
61 61 def __str__(self): 62 62 return self.phone 63 63 64 class NotRequiredFile(models.Model): 65 description = models.CharField(maxlength=50) 66 file = models.FileField(upload_to='files', blank=True) 67 68 def __str__(self): 69 return self.description 70 71 class RequiredFile(models.Model): 72 description = models.CharField(maxlength=50) 73 file = models.FileField(upload_to='files') 74 75 def __str__(self): 76 return self.description 77 64 78 __test__ = {'API_TESTS': """ 65 79 >>> from django.newforms import form_for_model, form_for_instance, save_instance, BaseForm, Form, CharField 66 80 >>> import datetime … … 377 391 378 392 >>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False) 379 393 >>> print f.clean('') 394 395 Test for filefield 396 397 >>> form_data = {'description': 'FileField test', 'file': {'content': 'FileField test', 'filename': 'filetest.txt'} } 398 >>> no_file_form_data = {'description': 'FileField test'} 399 >>> bad_encoding_form_data = {'description': 'FileField test', 'file': 'wrong encoding'} 400 >>> TestRequiredFileForm = form_for_model(RequiredFile) 401 >>> empty_required_fileform = TestRequiredFileForm(auto_id=False) 402 >>> print empty_required_fileform.as_ul() 403 <li>Description: <input type="text" name="description" maxlength="50" /></li> 404 <li>File: <input type="file" name="file" /></li> 405 406 Test with data 407 >>> filled_required_fileform= TestRequiredFileForm(form_data, auto_id=False) 408 >>> filled_required_fileform.is_valid() 409 True 410 411 >>> required_file_instance = filled_required_fileform.save() 412 >>> print required_file_instance.file 413 files/filetest.txt 414 >>> TestInstanceRequiredFileForm = form_for_instance(required_file_instance) 415 >>> instance_required_fileform = TestInstanceRequiredFileForm(auto_id=False) 416 >>> instance_required_fileform.as_ul() 417 u'<li>Description: <input type="text" name="description" value="FileField test" maxlength="50" /></li>\\n<li>File: <input type="file" name="file" /></li>' 418 >>> required_file_instance.delete() 419 420 Bad data test 421 >>> filled_required_fileform=TestRequiredFileForm(no_file_form_data) 422 >>> filled_required_fileform.is_valid() 423 False 424 >>> print filled_required_fileform.errors 425 <ul class="errorlist"><li>file<ul class="errorlist"><li>This field is required.</li></ul></li></ul> 426 >>> TestNotRequiredFileForm = form_for_model(NotRequiredFile) 427 >>> filled_not_required_fileform=TestNotRequiredFileForm(no_file_form_data) 428 >>> filled_not_required_fileform.is_valid() 429 True 430 >>> filled_not_required_fileform=TestNotRequiredFileForm(bad_encoding_form_data) 431 >>> print filled_not_required_fileform.errors 432 <ul class="errorlist"><li>file<ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul></li></ul> 380 433 None 381 434 >>> f.clean('') 382 435 >>> f.clean('1') -
tests/regressiontests/forms/tests.py
=== tests/regressiontests/forms/tests.py ==================================================================
168 168 # FileInput Widget ############################################################ 169 169 170 170 >>> w = FileInput() 171 >>> w.render('email', '') 172 u'<input type="file" name="email" />' 173 >>> w.render('email', None) 174 u'<input type="file" name="email" />' 175 >>> w.render('email', 'test@example.com') 176 u'<input type="file" name="email" value="test@example.com" />' 177 >>> w.render('email', 'some "quoted" & ampersanded value') 178 u'<input type="file" name="email" value="some "quoted" & ampersanded value" />' 179 >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) 180 u'<input type="file" name="email" value="test@example.com" class="fun" />' 171 >>> w.render('file', '') 172 u'<input type="file" name="file" />' 181 173 182 You can also pass 'attrs' to the constructor:183 >>> w = FileInput(attrs={'class': 'fun'})184 >>> w.render('email', '')185 u'<input type="file" class="fun" name="email" />'186 >>> w.render('email', 'foo@example.com')187 u'<input type="file" class="fun" value="foo@example.com" name="email" />'188 189 >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})190 u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'191 192 174 # Textarea Widget ############################################################# 193 175 194 176 >>> w = Textarea()