Commit 392d992f authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #7048 -- Added ClearableFileInput widget to clear file fields. Thanks...

Fixed #7048 -- Added ClearableFileInput widget to clear file fields. Thanks for report and patch, jarrow and Carl Meyer.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13968 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent a64e96c2
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -198,6 +198,13 @@ p.file-upload {
    margin-left: 5px;
}

span.clearable-file-input label {
	color: #333;
    font-size: 11px;
	display: inline;
    float: none;
}

/* CALENDARS & CLOCKS */

.calendarbox, .clockbox {
+5 −13
Original line number Diff line number Diff line
@@ -85,20 +85,12 @@ class AdminRadioFieldRenderer(RadioFieldRenderer):
class AdminRadioSelect(forms.RadioSelect):
    renderer = AdminRadioFieldRenderer

class AdminFileWidget(forms.FileInput):
    """
    A FileField Widget that shows its current value if it has one.
    """
    def __init__(self, attrs={}):
        super(AdminFileWidget, self).__init__(attrs)
class AdminFileWidget(forms.ClearableFileInput):
    template_with_initial = (u'<p class="file-upload">%s</p>'
                            % forms.ClearableFileInput.template_with_initial)
    template_with_clear = (u'<span class="clearable-file-input">%s</span>'
                           % forms.ClearableFileInput.template_with_clear)

    def render(self, name, value, attrs=None):
        output = []
        if value and hasattr(value, "url"):
            output.append('%s <a target="_blank" href="%s">%s</a> <br />%s ' % \
                (_('Currently:'), value.url, value, _('Change:')))
        output.append(super(AdminFileWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))

class ForeignKeyRawIdWidget(forms.TextInput):
    """
+9 −1
Original line number Diff line number Diff line
@@ -282,7 +282,15 @@ class FileField(Field):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))

    def save_form_data(self, instance, data):
        if data:
        # Important: None means "no change", other false value means "clear"
        # This subtle distinction (rather than a more explicit marker) is
        # needed because we need to consume values that are also sane for a
        # regular (non Model-) Form to find in its cleaned_data dictionary.
        if data is not None:
            # This value will be converted to unicode and stored in the
            # database, so leaving False as-is is not acceptable.
            if not data:
                data = ''
            setattr(instance, self.name, data)

    def formfield(self, **kwargs):
+38 −3
Original line number Diff line number Diff line
@@ -27,8 +27,9 @@ from django.core.validators import EMPTY_VALUES

from util import ErrorList
from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, \
        FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, \
        DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
        ClearableFileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, \
        DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget, \
        FILE_INPUT_CONTRADICTION

__all__ = (
    'Field', 'CharField', 'IntegerField',
@@ -108,6 +109,9 @@ class Field(object):
        if self.localize:
            widget.is_localized = True

        # Let the widget know whether it should display as required.
        widget.is_required = self.required

        # Hook into self.widget_attrs() for any Field-specific HTML attributes.
        extra_attrs = self.widget_attrs(widget)
        if extra_attrs:
@@ -167,6 +171,17 @@ class Field(object):
        self.run_validators(value)
        return value

    def bound_data(self, data, initial):
        """
        Return the value that should be shown for this field on render of a
        bound form, given the submitted POST data for the field and the initial
        data, if any.

        For most fields, this will simply be data; FileFields need to handle it
        a bit differently.
        """
        return data

    def widget_attrs(self, widget):
        """
        Given a Widget instance (*not* a Widget class), returns a dictionary of
@@ -434,12 +449,13 @@ class EmailField(CharField):
    default_validators = [validators.validate_email]

class FileField(Field):
    widget = FileInput
    widget = ClearableFileInput
    default_error_messages = {
        'invalid': _(u"No file was submitted. Check the encoding type on the form."),
        'missing': _(u"No file was submitted."),
        'empty': _(u"The submitted file is empty."),
        'max_length': _(u'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
        'contradiction': _(u'Please either submit a file or check the clear checkbox, not both.')
    }

    def __init__(self, *args, **kwargs):
@@ -468,10 +484,29 @@ class FileField(Field):
        return data

    def clean(self, data, initial=None):
        # If the widget got contradictory inputs, we raise a validation error
        if data is FILE_INPUT_CONTRADICTION:
            raise ValidationError(self.error_messages['contradiction'])
        # False means the field value should be cleared; further validation is
        # not needed.
        if data is False:
            if not self.required:
                return False
            # If the field is required, clearing is not possible (the widget
            # shouldn't return False data in that case anyway). False is not
            # in validators.EMPTY_VALUES; if a False value makes it this far
            # it should be validated from here on out as None (so it will be
            # caught by the required check).
            data = None
        if not data and initial:
            return initial
        return super(FileField, self).clean(data)

    def bound_data(self, data, initial):
        if data in (None, FILE_INPUT_CONTRADICTION):
            return initial
        return data

class ImageField(FileField):
    default_error_messages = {
        'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
+2 −4
Original line number Diff line number Diff line
@@ -437,10 +437,8 @@ class BoundField(StrAndUnicode):
            if callable(data):
                data = data()
        else:
            if isinstance(self.field, FileField) and self.data is None:
                data = self.form.initial.get(self.name, self.field.initial)
            else:
                data = self.data
            data = self.field.bound_data(
                self.data, self.form.initial.get(self.name, self.field.initial))
        data = self.field.prepare_value(data)

        if not only_initial:
Loading