-
-
Save epigos/f3832e5a74d292c9fddda7f0d1179440 to your computer and use it in GitHub Desktop.
Django widget to replace the file selection standard button by an image preview. Tested with Django 1.8.5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.forms import ModelForm, FileField | |
from .models import Campaign | |
from .widgets import ImagePreviewWidget | |
class DesignCampaignForm(ModelForm): | |
brand_logo = FileField(widget=ImagePreviewWidget) | |
class Meta: | |
model = Campaign | |
fields = ['brand_logo', 'brand_description'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Hide the input element for the image-preview widgets. | |
The "open file" dialog will be triggered by a click on the image preview */ | |
input[type="file"].image-preview { | |
display: none; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function ImageRefresher() { | |
}; | |
function init(inputId) { | |
var that = this; | |
this.inputId = '#' + inputId; | |
this.imgId = '#' + inputId + '_img'; | |
this.origData = $(this.imgId).attr('src'); | |
$(this.inputId).change(function(){ | |
that.readURL(this); | |
}); | |
} | |
function readURL(input) { | |
var that = this; | |
if (input.files && input.files[0]) { | |
var reader = new FileReader(); | |
reader.onload = function (e) { | |
$(that.imgId).attr('src', e.target.result); | |
} | |
reader.readAsDataURL(input.files[0]); | |
} else { | |
$(this.imgId).attr('src', this.origData); | |
} | |
} | |
ImageRefresher.prototype.init = init; | |
ImageRefresher.prototype.readURL = readURL; | |
window.onload = function() { | |
$('.image-preview').each(function(index) { | |
var refresher = new ImageRefresher(); | |
refresher.init(this.id); | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.forms.widgets import ClearableFileInput, Input, CheckboxInput | |
from django.utils.safestring import mark_safe | |
from django.utils.html import conditional_escape, format_html, html_safe | |
class ImagePreviewWidget(ClearableFileInput): | |
'''Basically a ClearableFileInput widget, but: | |
- remove from the template most clutter: we leave only the image, the clear and the <input> | |
- we define a class for the input, so that we can hide it with CSS | |
''' | |
# The "for" in the <label> allows to open the "open file" dialog by clicking on the image, no js involved | |
template_with_initial = ( | |
'<label for=%(id_for_label)s><img id="%(img_id)s" src="/media/%(initial)s" width="100px"></label>' | |
'%(clear_template)s<br />%(input)s' | |
) | |
INPUT_CLASS = 'image-preview' # This is the class of the <input> element, which we want to hide | |
def __init__(self, attrs=None): | |
super(ImagePreviewWidget, self).__init__(attrs) | |
self.attrs['class'] = self.INPUT_CLASS | |
# Override ClearableFileInput:render | |
def render(self, name, value, attrs=None): | |
id_for_label = self.id_for_label(attrs.get('id')) | |
substitutions = { | |
'initial_text': self.initial_text, | |
'input_text': self.input_text, | |
'clear_template': '', | |
'clear_checkbox_label': self.clear_checkbox_label, | |
# We need the id, so that clicking in the image triggers the "Open file" native window | |
'id_for_label': id_for_label, | |
# | |
'img_id': id_for_label + '_img', | |
} | |
template = '%(input)s' | |
substitutions['input'] = Input.render(self, name, value, attrs) # call Input.render directly | |
if self.is_initial(value): | |
template = self.template_with_initial | |
substitutions.update(self.get_template_substitution_values(value)) | |
if not self.is_required: | |
checkbox_name = self.clear_checkbox_name(name) | |
checkbox_id = self.clear_checkbox_id(checkbox_name) | |
substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name) | |
substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id) | |
substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id}) | |
substitutions['clear_template'] = self.template_with_clear % substitutions | |
return mark_safe(template % substitutions) | |
class Media: | |
css = { | |
'all': ('css/image-preview-widget.css',) | |
} | |
js = ('js/image-preview-widget.js', ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Philip, thanks for this very useful widget. I have implemented your code, and get the following result for my image:

instead of the current filename, without having to select it. Any ideas ? or am I doing something wrong ?
which has the link to display the .png file. Is this the expected result? Ideally I would like to see the image as thumbnail in my order form,