Search code examples
djangodjango-formsdjango-grappellidjango-import-export

django-import-export form <input> not rendering in custom admin template w/ grappelli


after implementing django-import-export on a project using django-grappelli for admin UI, I've discovered there are some CSS incompatibilities between the two libs: https://github.com/sehmaschine/django-grappelli/issues/435

to address this, I created custom admin template overwrites so import-export uses grappelli's CSS:

/templates/admin/import_export/base.html

{% extends "admin/base_site.html" %}
{% load i18n admin_static admin_modify %}
{% load admin_urls %}

{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<ul>
    <li><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
    <li><a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_label|capfirst|escape }}</a></li>
    <li><a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a></li>
    <li> {% block breadcrumbs_last %}{% endblock %}</li>
</ul>

{% endblock %}
{% endif %}

/templates/admin/import_export/change_list.html

{% extends "admin/change_list.html" %}
{% load i18n grp_tags %}

{# Original template renders object-tools only when has_add_permission is True. #}
{# This hack allows sub templates to add to object-tools #}
{% block object-tools %}
  <ul class="grp-object-tools">
    {% block object-tools-items %}
      {% if has_add_permission %}
        {{ block.super }}
      {% endif %}
    {% endblock %}
  </ul>
{% endblock %}

/templates/admin/import_export/import.html

{% extends "admin/import_export/base.html" %}
{% load i18n grp_tags %}
{% load admin_urls %}
{% load import_export_tags %}

{% block breadcrumbs_last %}
{% trans "Import" %}
{% endblock %}

{% block content %}
{% if confirm_form %}
  <form action="{% url opts|admin_urlname:'process_import' %}" method="POST">
    {% csrf_token %}
    {{ confirm_form.as_p }}
    <p>
      {% trans "Below is a preview of data to be imported. If you are satisfied with the results, click 'Confirm import'" %}
    </p>
    <div class="grp-form-row grp-submit-row">
      <input type="submit" class="grp-button grp-default" name="confirm" value="{% trans 'Confirm import' %}">
    </div>
  </form>

{% else %}
  <form action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
    <div class="grp-form-row"><p>
      {% trans "This importer will import the following fields: " %}
      <code>{{ fields|join:", " }}</code>
    </p></div>

    <fieldset class="module aligned">
      {% for field in form %}
        <div class="grp-form-row">
          {{ field.errors }}

          <div class="c-1">{{ field.label_tag }}</div>

          <div class="c-2">{{ field }}

          {% if field.field.help_text %}
          <p class="help grp-help">{{ field.field.help_text|safe }}</p>
          </div>
          {% endif %}
        </div>
      {% endfor %}
    </fieldset>

    <div class="grp-form-row grp-submit-row">
      <input type="submit" class="grp-button grp-default" value="{% trans 'Submit' %}">
    </div>
    </div>
</form>
{% endif %}

{% if result %}

  {% if result.has_errors %}
    <h2>{% trans "Errors" %}</h2>
    <ul>
      {% for error in result.base_errors  %}
      <li>
        {{ error.error }}
        <div class="traceback errornote">{{ error.traceback|linebreaks }}</div>
      </li>
      {% endfor %}
      {% for line, errors in result.row_errors %}
        {% for error in errors %}
          <li>
            {% trans "Line number" %}: {{ line }} - {{ error.error }}
            <div><code>{{ error.row.values|join:", " }}</code></div>
            <div class="traceback errornote">{{ error.traceback|linebreaks }}</div>
          </li>
        {% endfor %}
      {% endfor %}
    </ul>
  {% else %}

  <h2>
    {% trans "Preview" %}
  </h2>
  <table>
    <thead>
      <tr>
        <th></th>
        {% for field in result.diff_headers %}
          <th>{{ field }}</th>
        {% endfor %}
      </tr>
    </thead>
    {% for row in result.rows %}
    <tr>
      <td>
        {% if row.import_type == 'new' %}
          {% trans "New" %}
        {% elif row.import_type == 'skip' %}
          {% trans "Skipped" %}
        {% elif row.import_type == 'delete' %}
          {% trans "Delete" %}
        {% elif row.import_type == 'update' %}
          {% trans "Update" %}
        {% endif %}
      </td>
      {% for field in row.diff %}
      <td>
        {{ field }}
      </td>
      {% endfor %}
    </tr>
    {% endfor %}
  </table>
  {% endif %}

  {% endif %}
{% endblock %}

but then, if I go to /admin/foo/object/import/ (ObjectAdmin would be an instance of ImportExportModelAdmin from import_export.admin), the input elements in my form isn't displaying in the admin view, even though I've modeled them after grappelli's .grp-button .grp-default CSS classes (and can see grappelli uses input elements in its own docs)

no form input

there's some issue with this part of the form I can't figure out:

<div class="grp-module grp-submit-row">
      <input type="submit" class="grp-button grp-default" value="{% trans 'Submit' %}">
    </div>

this is true for both import and export views. I can see the rest of the import and export forms, just not the form submit inputs.

project is Django version 1.9 django-grappelli==2.10.1 django-import-export==1.0.0


Solution

  • I'd still be interested in understanding why the form inputs wouldn't display, but I replaced the inputs with buttons to perform the same action and those display and the admin form now works.

    ex, replace:

    <input type="submit" value="{% trans 'Submit' %}" class="grp-button grp-default" />
    

    with:

    <button type="submit" class="grp-button" title="{% trans 'Submit' %}" value="{% trans 'Submit' %}">{% trans 'Submit' %}</button>