Ticket #6302: pass_initial_through_with_tests_mulitvaluefield.diff

File pass_initial_through_with_tests_mulitvaluefield.diff, 15.2 KB (added by Øyvind Saltvik <oyvind@…>, 16 years ago)

MultiValueField works too, is this overkill?

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

     
    797797        return os.path.normpath(f)
    798798
    799799    def save_form_data(self, instance, data):
    800         if data:
     800        from django.newforms.fields import UploadedFile
     801        if data and isinstance(data, UploadedFile):
    801802            getattr(instance, "save_%s_file" % self.name)(data.filename, data.content, save=False)
    802803
    803804    def formfield(self, **kwargs):
    804805        defaults = {'form_class': forms.FileField}
    805         # If a file has been provided previously, then the form doesn't require
    806         # that a new file is provided this time.
    807         if 'initial' in kwargs:
    808             defaults['required'] = False
    809806        defaults.update(kwargs)
    810807        return super(FileField, self).formfield(**defaults)
    811808
  • django/newforms/fields.py

     
    428428
    429429class FileField(Field):
    430430    widget = FileInput
     431    takes_initial = True
    431432    default_error_messages = {
    432433        'invalid': _(u"No file was submitted. Check the encoding type on the form."),
    433434        'missing': _(u"No file was submitted."),
     
    437438    def __init__(self, *args, **kwargs):
    438439        super(FileField, self).__init__(*args, **kwargs)
    439440
    440     def clean(self, data):
    441         super(FileField, self).clean(data)
     441    def clean(self, data, initial=None):
     442        super(FileField, self).clean(initial or data)
    442443        if not self.required and data in EMPTY_VALUES:
    443             return None
     444            return initial or None
     445        elif not data and initial:
     446            return initial
    444447        try:
    445448            f = UploadedFile(data['filename'], data['content'])
    446449        except TypeError:
     
    456459        'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
    457460    }
    458461
    459     def clean(self, data):
     462    def clean(self, data, initial=None):
    460463        """
    461464        Checks that the file-upload field data contains a valid image (GIF, JPG,
    462465        PNG, possibly others -- whatever the Python Imaging Library supports).
    463466        """
    464         f = super(ImageField, self).clean(data)
     467        f = super(ImageField, self).clean(data, initial)
    465468        if f is None:
    466469            return None
    467470        from PIL import Image
     
    614617        return new_value
    615618
    616619class ComboField(Field):
     620    takes_initial = True
     621
    617622    """
    618623    A Field whose clean() method calls multiple Field clean() methods.
    619624    """
     
    626631            f.required = False
    627632        self.fields = fields
    628633
    629     def clean(self, value):
     634    def clean(self, value, initial=None):
    630635        """
    631636        Validates the given value against all of self.fields, which is a
    632637        list of Field instances.
    633638        """
    634         super(ComboField, self).clean(value)
     639        super(ComboField, self).clean(initial or value)
    635640        for field in self.fields:
    636             value = field.clean(value)
     641            if hasattr(field, 'takes_initial'):
     642                value = field.clean(value, initial)
     643            else:
     644                value = field.clean(value)
    637645        return value
    638646
    639647class MultiValueField(Field):
     
    653661
    654662    You'll probably want to use this with MultiWidget.
    655663    """
     664    takes_initial = True
    656665    default_error_messages = {
    657666        'invalid': _(u'Enter a list of values.'),
    658667    }
     
    666675            f.required = False
    667676        self.fields = fields
    668677
    669     def clean(self, value):
     678    def clean(self, value, initial=None):
    670679        """
    671680        Validates every value in the given list. A value is validated against
    672681        the corresponding Field in self.fields.
     
    675684        fields=(DateField(), TimeField()), clean() would call
    676685        DateField.clean(value[0]) and TimeField.clean(value[1]).
    677686        """
    678         clean_data = []
     687        clean_data, value_list, initial_list, takes_initial_list = [], [], [], []
     688        value, initial = value or [], initial or []
    679689        errors = ErrorList()
    680690        if not value or isinstance(value, (list, tuple)):
    681             if not value or not [v for v in value if v not in EMPTY_VALUES]:
     691            for i, field in enumerate(self.fields):
     692                try:
     693                    field_value = value[i]
     694                except IndexError:
     695                    field_value = None
     696                value_list.append(field_value)
     697                try:
     698                    field_initial = initial[i]
     699                except IndexError:
     700                    field_initial = None
     701                initial_list.append(field_initial)
     702                takes_initial_list.append(hasattr(field, 'takes_initial'))
     703
     704            if not value or not [(v, i, t) for v, i, t in \
     705                zip(value_list, initial_list, takes_initial_list) \
     706                if v not in EMPTY_VALUES or t and i not in EMPTY_VALUES]:
     707
    682708                if self.required:
    683709                    raise ValidationError(self.error_messages['required'])
    684710                else:
    685711                    return self.compress([])
    686712        else:
    687713            raise ValidationError(self.error_messages['invalid'])
     714
    688715        for i, field in enumerate(self.fields):
     716            field_value = value_list[i]
     717            field_initial = initial_list[i]
     718            takes_initial = takes_initial_list[i]
     719            if self.required and not ( (takes_initial and field_initial not in EMPTY_VALUES) or
     720                (field_value not in EMPTY_VALUES) ):
     721                 raise ValidationError(self.error_messages['required'])
    689722            try:
    690                 field_value = value[i]
    691             except IndexError:
    692                 field_value = None
    693             if self.required and field_value in EMPTY_VALUES:
    694                 raise ValidationError(self.error_messages['required'])
    695             try:
    696                 clean_data.append(field.clean(field_value))
     723                if takes_initial:
     724                    clean_data.append(field.clean(field_value, field_initial))
     725                else:
     726                    clean_data.append(field.clean(field_value))
    697727            except ValidationError, e:
    698728                # Collect all validation errors in a single list, which we'll
    699729                # raise at the end of clean(), rather than raising a single
     
    701731                errors.extend(e.messages)
    702732        if errors:
    703733            raise ValidationError(errors)
    704         return self.compress(clean_data)
     734        return self.compress(clean_data, initial_list)
    705735
    706     def compress(self, data_list):
     736    def compress(self, data_list, initial_list=[]):
    707737        """
    708738        Returns a single value for the given list of values. The values can be
    709739        assumed to be valid.
     
    730760        )
    731761        super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
    732762
    733     def compress(self, data_list):
     763    def compress(self, data_list, initial_list=[]):
    734764        if data_list:
    735765            # Raise a validation error if time or date is empty
    736766            # (possible if SplitDateTimeField has required=False).
  • django/newforms/forms.py

     
    182182            # widgets split data over several HTML fields.
    183183            value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
    184184            try:
    185                 value = field.clean(value)
     185                if hasattr(field, 'takes_initial'):
     186                    initial = self.initial.get(name, field.initial)
     187                    value = field.clean(value, initial)
     188                else:
     189                    value = field.clean(value)
    186190                self.cleaned_data[name] = value
    187191                if hasattr(self, 'clean_%s' % name):
    188192                    value = getattr(self, 'clean_%s' % name)()
  • tests/modeltests/model_forms/models.py

     
    77most of these tests should be rewritten.
    88"""
    99
     10import os
     11import tempfile
     12
    1013from django.db import models
    1114
    1215ARTICLE_STATUS = (
     
    5558    def __unicode__(self):
    5659        return self.phone
    5760
     61class TextFile(models.Model):
     62    description = models.CharField(max_length=20)
     63    file = models.FileField(upload_to=tempfile.gettempdir())
     64
     65    def __unicode__(self):
     66        return self.description
     67
    5868__test__ = {'API_TESTS': """
    5969>>> from django import newforms as forms
    6070>>> from django.newforms.models import ModelForm
     
    701711True
    702712>>> f.cleaned_data
    703713{'phone': u'312-555-1212', 'description': u'Assistance'}
     714
     715# FileField ###################################################################
     716
     717>>> class TextFileForm(ModelForm):
     718...     class Meta:
     719...         model = TextFile
     720
     721Test conditions when files is either not given or empty.
     722
     723>>> f = TextFileForm(data={'description': u'Assistance'})
     724>>> f.is_valid()
     725False
     726>>> f = TextFileForm(data={'description': u'Assistance'}, files={})
     727>>> f.is_valid()
     728False
     729
     730Upload a file and ensure it all works as expected.
     731
     732>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test1.txt', 'content': 'hello world'}})
     733>>> f.is_valid()
     734True
     735>>> type(f.cleaned_data['file'])
     736<class 'django.newforms.fields.UploadedFile'>
     737>>> instance = f.save()
     738>>> instance.file
     739u'.../test1.txt'
     740
     741Edit an instance that already has the file defined in the model. This will not
     742save the file again, but leave it exactly as it is.
     743
     744>>> f = TextFileForm(data={'description': u'Assistance'}, instance=instance)
     745>>> f.is_valid()
     746True
     747>>> f.cleaned_data['file']
     748u'.../test1.txt'
     749>>> instance = f.save()
     750>>> instance.file
     751u'.../test1.txt'
     752
     753Delete the current file since this is not done by Django.
     754
     755>>> os.unlink(instance.get_file_filename())
     756
     757Override the file by uploading a new one.
     758
     759>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test2.txt', 'content': 'hello world'}}, instance=instance)
     760>>> f.is_valid()
     761True
     762>>> instance = f.save()
     763>>> instance.file
     764u'.../test2.txt'
     765
     766>>> instance.delete()
     767
     768Test the non-required FileField
     769
     770>>> f = TextFileForm(data={'description': u'Assistance'})
     771>>> f.fields['file'].required = False
     772>>> f.is_valid()
     773True
     774>>> instance = f.save()
     775>>> instance.file
     776''
     777
     778>>> f = TextFileForm(data={'description': u'Assistance'}, files={'file': {'filename': 'test3.txt', 'content': 'hello world'}}, instance=instance)
     779>>> f.is_valid()
     780True
     781>>> instance = f.save()
     782>>> instance.file
     783u'.../test3.txt'
     784>>> instance.delete()
    704785"""}
  • tests/regressiontests/forms/extra.py

     
    209209...         )
    210210...         super(ComplexField, self).__init__(fields, required, widget, label, initial)
    211211...
    212 ...     def compress(self, data_list):
     212...     def compress(self, data_list, initial_list=[]):
    213213...         if data_list:
    214214...             return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2])
    215215...         return None
  • tests/regressiontests/forms/fields.py

     
    749749...
    750750ValidationError: [u'This field is required.']
    751751
     752>>> f.clean('', '')
     753Traceback (most recent call last):
     754...
     755ValidationError: [u'This field is required.']
     756
     757>>> f.clean('', 'files/test1.pdf')
     758'files/test1.pdf'
     759
    752760>>> f.clean(None)
    753761Traceback (most recent call last):
    754762...
    755763ValidationError: [u'This field is required.']
    756764
     765>>> f.clean(None, '')
     766Traceback (most recent call last):
     767...
     768ValidationError: [u'This field is required.']
     769
     770>>> f.clean(None, 'files/test2.pdf')
     771'files/test2.pdf'
     772
    757773>>> f.clean({})
    758774Traceback (most recent call last):
    759775...
    760776ValidationError: [u'No file was submitted.']
    761777
     778>>> f.clean({}, '')
     779Traceback (most recent call last):
     780...
     781ValidationError: [u'No file was submitted.']
     782
     783>>> f.clean({}, 'files/test3.pdf')
     784'files/test3.pdf'
     785
    762786>>> f.clean('some content that is not a file')
    763787Traceback (most recent call last):
    764788...
    765789ValidationError: [u'No file was submitted. Check the encoding type on the form.']
    766790
    767 >>> f.clean({'filename': 'name', 'content':None})
     791>>> f.clean({'filename': 'name', 'content': None})
    768792Traceback (most recent call last):
    769793...
    770794ValidationError: [u'The submitted file is empty.']
    771795
    772 >>> f.clean({'filename': 'name', 'content':''})
     796>>> f.clean({'filename': 'name', 'content': ''})
    773797Traceback (most recent call last):
    774798...
    775799ValidationError: [u'The submitted file is empty.']
    776800
    777 >>> type(f.clean({'filename': 'name', 'content':'Some File Content'}))
     801>>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}))
    778802<class 'django.newforms.fields.UploadedFile'>
    779803
     804>>> unicode(f.clean({'filename': 'name', 'content': 'Some File Content'}))
     805u'name'
     806
     807>>> type(f.clean({'filename': 'name', 'content': 'Some File Content'}, 'files/test4.pdf'))
     808<class 'django.newforms.fields.UploadedFile'>
     809
    780810# URLField ##################################################################
    781811
    782812>>> f = URLField()
     
    11051135u''
    11061136>>> f.clean(None)
    11071137u''
     1138>>> f = ComboField(fields=[FileField(), CharField(max_length=20)])
     1139>>> f.clean('data', 'some_file.txt')
     1140Traceback (most recent call last):
     1141...   
     1142ValidationError: [u'No file was submitted. Check the encoding type on the form.']
     1143>>> f.clean('', 'some_file.txt')
     1144u'some_file.txt'
     1145>>> f.clean('', None)
     1146Traceback (most recent call last):
     1147...
     1148ValidationError: [u'This field is required.']
     1149>>> f.clean({'filename': 'filename.txt', 'content':'something'})
     1150u'filename.txt'
     1151>>> f.clean({'filename': 'too_long_filename_for_this_combofield_here.txt', 'content':'something'})
     1152Traceback (most recent call last):
     1153...
     1154ValidationError: [u'Ensure this value has at most 20 characters (it has 46).']
    11081155
     1156# MultiValueField ##########################################################
     1157
     1158>>> f = MultiValueField(fields=[FileField(), CharField(max_length=20)])
     1159>>> f.clean([{'filename': 'some_file.txt', 'content':'something'}, 'Some text'])
     1160Traceback (most recent call last):
     1161...
     1162NotImplementedError: Subclasses must implement this method.
     1163>>> f.clean([{'filename': 'some_file.txt', 'content':'something'}, 'alotoftext_more_than_20_chars'])
     1164Traceback (most recent call last):
     1165...
     1166ValidationError: [u'Ensure this value has at most 20 characters (it has 29).']
     1167>>> f.clean([None, None])
     1168Traceback (most recent call last):
     1169...
     1170ValidationError: [u'This field is required.']
     1171>>> f.clean([None, 'Some text'], ['some_file.txt', None])
     1172Traceback (most recent call last):
     1173...
     1174NotImplementedError: Subclasses must implement this method.
     1175
    11091176# SplitDateTimeField ##########################################################
    11101177
    11111178>>> f = SplitDateTimeField()
Back to Top