Ticket #6033: is_empty_clean_field.3.diff

File is_empty_clean_field.3.diff, 7.9 KB (added by Øyvind Saltvik <oyvind@…>, 7 years ago)

Patched against the correct path/ includes patch from #5828

  • django/newforms/formsets.py

     
    116116        self.deleted_data = []
    117117        # Process change forms
    118118        for form in self.change_forms:
    119             if form.is_valid():
    120                 if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
    121                     self.deleted_data.append(form.cleaned_data)
     119            if form.is_valid() or self.deletable:
     120                if self.deletable and self.clean_field(form, DELETION_FIELD_NAME):
     121                    self.deleted_data.append({DELETION_FIELD_NAME: True})
     122                elif form.is_valid():
     123                    self.cleaned_data.append(form.cleaned_data)
    122124                else:
    123                     self.cleaned_data.append(form.cleaned_data)
    124             else:
    125                 self._is_valid = False
     125                    self._is_valid = False
    126126            errors.append(form.errors)
    127127        # Process add forms in reverse so we can easily tell when the remaining
    128128        # ones should be required.
     
    168168        """
    169169        return self.cleaned_data
    170170
     171    def clean_field(self, form, f):
     172        if f in form.fields:
     173            field = form.fields.get(f)
     174            value = field.widget.value_from_datadict(self.data, self.files, '%s-%s' % (form.prefix, f))
     175            try:
     176                value = field.clean(value)
     177                if hasattr(self, 'clean_%s' % f):
     178                    value = getattr(self, 'clean_%s' % f)()
     179            except ValidationError, e:
     180                return False
     181            return value
     182        else:
     183            return False
     184               
    171185    def add_fields(self, form, index):
    172186        """A hook for adding extra fields on to each form instance."""
    173187        if self.orderable:
  • django/newforms/models.py

     
    294294            existing_objects[obj._get_pk_val()] = obj
    295295        saved_instances = []
    296296        for form in self.change_forms:
    297             obj = existing_objects[form.cleaned_data[self.model._meta.pk.attname]]
    298             if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
     297            obj = existing_objects[self.clean_field(form, self.model._meta.pk.attname)]
     298            if self.deletable and self.clean_field(form, DELETION_FIELD_NAME):
    299299                obj.delete()
    300             else:
     300            elif self.is_valid():
    301301                saved_instances.append(self.save_instance(form, obj, commit=commit))
    302302        return saved_instances
    303303
     
    309309            # If someone has marked an add form for deletion, don't save the
    310310            # object. At some point it would be nice if we didn't display
    311311            # the deletion widget for add forms.
    312             if self.deletable and form.cleaned_data[DELETION_FIELD_NAME]:
     312            if self.deletable and self.clean_field(form, DELETION_FIELD_NAME):
    313313                continue
    314             new_objects.append(self.save_new(form, commit=commit))
     314            if self.is_valid():
     315                new_objects.append(self.save_new(form, commit=commit))
    315316        return new_objects
    316317
    317318    def add_fields(self, form, index):
  • django/newforms/forms.py

     
    189189        for name, field in self.fields.items():
    190190            if name in exceptions:
    191191                continue
    192             # value_from_datadict() gets the data from the dictionary.
     192            # value_from_datadict() gets the data from the data dictionaries.
    193193            # Each widget type knows how to retrieve its own data, because some
    194194            # widgets split data over several HTML fields.
    195195            value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
    196             # HACK: ['', ''] and [None, None] deal with SplitDateTimeWidget. This should be more robust.
    197             if value not in (None, '', ['', ''], [None, None]):
     196            if not field.widget.is_empty(value):
    198197                return False
    199198        return True
    200199
  • django/newforms/widgets.py

     
    164164        of this widget. Returns None if it's not provided.
    165165        """
    166166        return data.get(name, None)
     167   
     168    def is_empty(self, value):
     169        """
     170        Given a dictionary of data and this widget's name, return True if the
     171        widget data is empty or False when not empty.
     172        """
     173        if value not in (None, ''):
     174            return False
     175        return True
    167176
    168177    def id_for_label(self, id_):
    169178        """
     
    294303            # send results for unselected checkboxes.
    295304            return False
    296305        return super(CheckboxInput, self).value_from_datadict(data, files, name)
     306   
     307    def is_empty(self, value):
     308        # this widget will always either be True or False, so always return the
     309        # opposite value so False values will make the form empty
     310        return not value
    297311
    298312class Select(Widget):
    299313    def __init__(self, attrs=None, choices=()):
     
    333347    def value_from_datadict(self, data, files, name):
    334348        value = data.get(name, None)
    335349        return {u'2': True, u'3': False, True: True, False: False}.get(value, None)
     350   
     351    def is_empty(self, value):
     352        # this widget will always either be True, False or None, so always
     353        # return the opposite value so False and None values will make the
     354        # form empty.
     355        return not value
    336356
    337357class SelectMultiple(Widget):
    338358    def __init__(self, attrs=None, choices=()):
     
    521541
    522542    def value_from_datadict(self, data, files, name):
    523543        return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)]
     544   
     545    def is_empty(self, value):
     546        for widget, val in zip(self.widgets, value):
     547            if not widget.is_empty(val):
     548                return False
     549        return True
    524550
    525551    def format_output(self, rendered_widgets):
    526552        """
  • tests/regressiontests/forms/widgets.py

     
    282282>>> w.value_from_datadict({}, {}, 'testing')
    283283False
    284284
     285The CheckboxInput widget will always be empty when there is a False value
     286>>> w.is_empty(False)
     287True
     288>>> w.is_empty(True)
     289False
     290
    285291# Select Widget ###############################################################
    286292
    287293>>> w = Select()
     
    432438<option value="3" selected="selected">No</option>
    433439</select>
    434440
     441The NullBooleanSelect widget will always be empty when Unknown or No is selected
     442as its value.  This is to stay compliant with the CheckboxInput behavior
     443>>> w.is_empty(False)
     444True
     445>>> w.is_empty(None)
     446True
     447>>> w.is_empty(True)
     448False
     449
    435450""" + \
    436451r""" # [This concatenation is to keep the string below the jython's 32K limit].
    437452# SelectMultiple Widget #######################################################
     
    834849>>> w.render('name', ['john', 'lennon'])
    835850u'<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />'
    836851
     852The MultiWidget will be empty only when all widgets are considered empty.
     853>>> w.is_empty(['john', 'lennon'])
     854False
     855>>> w.is_empty(['john', ''])
     856False
     857>>> w.is_empty(['', ''])
     858True
     859>>> w.is_empty([None, None])
     860True
     861
    837862# SplitDateTimeWidget #########################################################
    838863
    839864>>> w = SplitDateTimeWidget()
Back to Top