Search code examples
djangocheckboxdjango-admindjango-modelsdjango-widget

Django ImageField widget to add thumbnail with clearable checkbox


I have a model like this

class Participation(models.Model):
    # ... some attributes ...
    thumbnail = models.ImageField(
        verbose_name='immagine di copertina',
        blank=True,
        null=True,
    )

and I add the following code to show a thumbnail in the admin page:

class AdminImageWidget(ClearableFileInput):
"""A ImageField Widget for admin that shows a thumbnail"""

def render(self, name, value, attrs=None):
    output = []
    if value and getattr(value, 'url', None):
        image_url = value.url
        file_name = str(value)
        output.append(
            u'%s '
            u'<a href="%s" target="_blank">'
            u'<img src="%s" alt="%s" style="max-width: 100px; max-height: 100px; border-radius: 5px;" />'
            u'</a><br/><br/>%s '
            % (_('Currently:'), image_url, image_url, file_name, _('Change:'))
        )
    output.append(super(ClearableFileInput, self).render(name, value, attrs))
    return mark_safe(u''.join(output))

Even if it worked fine for the thumbnail, the super(ClearableFileInput, self).render(name, value, attrs) calling is adding just the browse button, but it isn't showing the clear checkbox, so I cannot delete the selected thumbnail.

What's wrong with this code? How can I add the checkbox mantaining the thumbnail too?


Solution

  • I solved my problem recoding the AdminImageWidget as following:

    from django.utils.safestring import mark_safe
    from django.utils.html import escape, conditional_escape
    from django.utils.encoding import force_unicode
    from django.forms.widgets import ClearableFileInput, Input, CheckboxInput
    
    
    class AdminImageWidget(ClearableFileInput):
        def render(self, name, value, attrs=None):
            substitutions = {
                'initial_text': self.initial_text,
                'input_text': self.input_text,
                'clear_template': '',
                'clear_checkbox_label': self.clear_checkbox_label,
            }
            template = '%(input)s'
            substitutions['input'] = Input.render(self, name, value, attrs)
    
            if value and hasattr(value, "url"):
                template = self.template_with_initial
                substitutions['initial'] = (
                    '<img src="%s" alt="%s" style="max-width: 100px; max-height: 100px; border-radius: 5px;" /><br/>' % (
                        escape(value.url), escape(force_unicode(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)
    

    Note the:

    substitutions['initial'] = (
        '<img src="%s" alt="%s" style="max-width: 100px; max-height: 100px; border-radius: 5px;" /><br/>' % (
            escape(value.url), escape(force_unicode(value))
        )
    )
    

    that make possible to show the thumbnail.