How change html template of ImageField in edit form?

1.3k views Asked by At

I use Django 1.11 in my project. In my edit form I have ImageField. Django by default render html which you can see below. How change html of ImageField in edit form correctly?

I tried next code but Django raise error TemplateDoesNotExist. Django dont see template_file in my custom widget? How to fix this problem? By the way initial_text and input_text works well. Also I tried template_with_initial but unfortunately it didnt help me. I would be grateful for any help!

Django render this html by default:

Currently:
<a href="/media/images/2017/08/23/picture.jpg">images/2017/08/23/picture.jpg</a>
Change:
<input name="image" id="id_image" type="file">

widgets.py:

from django.forms.widgets import ClearableFileInput

class CustomClearableFileInput(ClearableFileInput):
    initial_text = 'Current image'

    input_text = 'Change'

    clear_checkbox_label = 'Clear Image'

    template_name = 'custom_clearable_file_input.html' <-- DONT WORK

custom_clearable_file_input.html:

{% if widget.is_initial %}
  <span>{{ widget.initial_text }}</span>: <a href="{{ widget.value.url }}">{{ widget.value }}</a>
  {% if not widget.required %}
    <input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}"/>
    <label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>
  {% endif %}
  <br/>
  <span>{{ widget.input_text }}</span>:
{% endif %}
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}/>

ERROR:

Traceback (most recent call last):
  File "/srv/envs/Project/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/home/nurzhan/CA/article/views.py", line 106, in get
    request=request
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/backends/django.py", line 68, in render
    reraise(exc, self.backend)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/backends/django.py", line 89, in reraise
    six.reraise(exc.__class__, new, sys.exc_info()[2])
  File "/srv/envs/Project/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/base.py", line 199, in _render
    return self.nodelist.render(context)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/base.py", line 993, in render
    bits.append(force_text(bit))
  File "/srv/envs/Project/lib/python3.6/site-packages/django/utils/encoding.py", line 76, in force_text
    s = six.text_type(s)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/utils/html.py", line 385, in <lambda>
    klass.__str__ = lambda self: mark_safe(klass_str(self))
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/boundfield.py", line 41, in __str__
    return self.as_widget()
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/boundfield.py", line 120, in as_widget
    **kwargs
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/widgets.py", line 221, in render
    return self._render(self.template_name, context, renderer)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/widgets.py", line 226, in _render
    return mark_safe(renderer.render(template_name, context))
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/renderers.py", line 31, in render
    template = self.get_template(template_name)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/forms/renderers.py", line 37, in get_template
    return self.engine.get_template(template_name)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/backends/django.py", line 41, in get_template
    reraise(exc, self)
  File "/srv/envs/Project/lib/python3.6/site-packages/django/template/backends/django.py", line 89, in reraise
    six.reraise(exc.__class__, new, sys.exc_info()[2])
  File "/srv/envs/kaseAdmPy362/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/srv/envs/kaseAdmPy362/lib/python3.6/site-packages/django/template/backends/django.py", line 39, in get_template
    return Template(self.engine.get_template(template_name), self)
  File "/srv/envs/kaseAdmPy362/lib/python3.6/site-packages/django/template/engine.py", line 162, in get_template
    template, origin = self.find_template(template_name)
  File "/srv/envs/kaseAdmPy362/lib/python3.6/site-packages/django/template/engine.py", line 148, in find_template
    raise TemplateDoesNotExist(name, tried=tried)
django.template.exceptions.TemplateDoesNotExist: custom_clearable_file_input.html
[24/Aug/2017 11:02:30] "GET /administration/article/47/edit/ HTTP/1.1" 500 
1

There are 1 answers

15
Paolo Melchiorre On BEST ANSWER

It depends from the path where your custom template file is stored.

As described in the form rendering documentations:

Django’s form widgets are rendered using Django’s template engines system.

The rendering of form templates is controlled by ... DjangoTemplates [renderer class].

[DjangoTemplates] renderer uses a standalone DjangoTemplates engine (unconnected to what you might have configured in the TEMPLATES setting). It loads templates first from the built-in form templates directory in django/forms/templates and then from the installed apps’ templates directories using the app_directories loader.

If you want to render templates with customizations from your TEMPLATES setting, such as context processors for example, use the TemplatesSetting renderer.

You have two options:

  1. Create a templates sub-directory inside your (app_name) folder and put your temmplate file in this folder. (/app_name/templates/custom_clearable_file_input.html)

  2. you can leave your template file in the global templates folder specified in your TEMPLATES['DIRS'] parameter of your settings.py file (/templates/custom_clearable_file_input.html) but you have to use TemplatesSetting renderer as specified in the TemplatesSettings documentation ( I added an example of customization for the settings.py file )

    import django
    ...
    INSTALLED_APPS = [
        ...
        'django.forms'
        ...
    ]
    ...
    TEMPLATES = [
        {
            ...
            'DIRS': [
                'templates',
                django.__path__[0] + '/forms/templates',
            ],
            'APP_DIRS': True,
    
            ...
        },
    ]
    ...
    FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'