Skip to content

Instantly share code, notes, and snippets.

@epigos
Forked from gonvaled/forms.py
Created February 24, 2017 10:26
Show Gist options
  • Save epigos/f3832e5a74d292c9fddda7f0d1179440 to your computer and use it in GitHub Desktop.
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
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']
/* 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;
}
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);
});
};
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', )
@JanineRoux
Copy link

Hi Philip, thanks for this very useful widget. I have implemented your code, and get the following result for my image:
image
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,
image instead of the current filename, without having to select it. Any ideas ? or am I doing something wrong ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment