官方实例:https://django-import-export.readthedocs.io/en/latest/getting_started.html#creating-import-export-resource

1.导入 导出

2.批量更新

3.如何导出model中 ForeignKey 字段的其它的属性值

 项目github地址:https://github.com/wangcongxing/OpenTheDoor

如何新建django项目请参照

Python Django 零基础破门而入篇(一)

 

1.安装 django-import-export

pip install django-import-export

Python Django 零基础破门而入篇(二)

 

2.配置项目文件下 settings.py

修改 INSTALLED_APPS

默认值为False。它确定库是否会在数据导入中使用数据库事务,以确保安全

新增 IMPORT_EXPORT_USE_TRANSACTIONS = True

 

Python Django 零基础破门而入篇(二)

 

3.修改app-->admin.py 设置导出代码列头 代码如下

from django.contrib import admin
from app import models
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from django.apps import apps

# Register your models here.
admin.site.site_header = "大佬管理"
admin.site.site_title = "大佬管理后台管理"


class bossInfoResource(resources.ModelResource):
    def __init__(self):
        super(bossInfoResource, self).__init__()

        field_list = models.bossInfo._meta.fields
        self.vname_dict = {}
        for i in field_list:
            self.vname_dict[i.name] = i.verbose_name

    # 默认导入导出field的column_name为字段的名称,这里修改为字段的verbose_name
    def get_export_fields(self):
        fields = self.get_fields()
        for field in fields:
            field_name = self.get_field_name(field)
            # 如果我们设置过verbose_name,则将column_name替换为verbose_name。否则维持原有的字段名
            if field_name in self.vname_dict.keys():
                field.column_name = self.vname_dict[field_name]
        return fields

    def after_import(self, dataset, result, using_transactions, dry_run, **kwargs):
        print("after_import")

    def after_import_instance(self, instance, new, **kwargs):
        print("after_import_instance")

    class Meta:
        model = models.bossInfo
        skip_unchanged = True
        report_skipped = True
        fields = (
        "id", "age", "gender", "likeFruit", "userUrl", "name", "desc", "createTime", "lastTime", "creator", "editor")


@admin.register(models.bossInfo)
class bossInfoAdmin(ImportExportModelAdmin):
    fields = (
        "name", "age", "gender",
        "likeFruit", "userUrl", "desc")
    list_display = (
        "name", "age", "gender",
        "likeFruit", "userUrl",
        "createTime",
        "lastTime",
        "creator", "editor")
    list_display_links = ("name",)
    exclude = ("createTime", "creator", "editor")
    search_fields = ("name",)
    list_filter = ("gender", "likeFruit")
    model_icon = "fa fa-tag"
    list_per_page = 20
    ordering = ["-id"]
    resource_class = bossInfoResource

    def save_model(self, request, obj, form, change):
        if form.is_valid():
            if change:
                obj.editor = request.user
            else:
                obj.creator = request.user
                obj.editor = request.user
                obj.save()
        super().save_model(request, obj, form, change)

 

 4.运行效果

Python Django 零基础破门而入篇(二)

Python Django 零基础破门而入篇(二)

 

Python Django 零基础破门而入篇(二)

5.导出excel 存在以下问题

1.创建者 / 修改者 如何显示用户名

2.创建时间 / 修改时间如何进行格式化

3.继续修改admin.py  重写导出 export 完整代码如下

from django.contrib import admin
from app import models
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from django.apps import apps
from django.db.models import QuerySet
import tablib
# Register your models here.
admin.site.site_header = "大佬管理"
admin.site.site_title = "大佬管理后台管理"


class bossInfoResource(resources.ModelResource):
    def __init__(self):
        super(bossInfoResource, self).__init__()

        field_list = models.bossInfo._meta.fields
        self.vname_dict = {}
        self.fkey = []
        for i in field_list:
            self.vname_dict[i.name] = i.verbose_name
            self.fkey.append(i.name)

    # 默认导入导出field的column_name为字段的名称,这里修改为字段的verbose_name
    def get_export_fields(self):
        fields = self.get_fields()
        for field in fields:
            field_name = self.get_field_name(field)
            # 如果我们设置过verbose_name,则将column_name替换为verbose_name。否则维持原有的字段名
            if field_name in self.vname_dict.keys():
                field.column_name = self.vname_dict[field_name]
        return fields

    def after_import(self, dataset, result, using_transactions, dry_run, **kwargs):
        print("after_import")

    def after_import_instance(self, instance, new, **kwargs):
        print("after_import_instance")

    # 重载resources.py的export方法,修改将要导出的data的某些外键相关数据。默认导出外键id,这里修改为导出外键对应的值
    def export(self, queryset=None, *args, **kwargs):
        self.before_export(queryset, *args, **kwargs)
        if queryset is None:
            queryset = self.get_queryset()
        headers = self.get_export_headers()
        data = tablib.Dataset(headers=headers)
        # 获取所有外键名称在headers中的位置
        fk_index = {}
        for fk in self.fkey:
            fk_index[fk] = headers.index(self.vname_dict[fk])
        # --------------------- #

        if isinstance(queryset, QuerySet):
            # Iterate without the queryset cache, to avoid wasting memory when
            # exporting large datasets.
            iterable = queryset.iterator()
        else:
            iterable = queryset
        for obj in iterable:
            # --------------------- #
            # 获取将要导出的源数据,这里export_resource返回的是列表,便于更改。替换到外键的值
            # 可以对所有字段值进行二次处理
            res = self.export_resource(obj)
            res[fk_index['id']] = obj.id
            res[fk_index['age']] = obj.age
            res[fk_index['gender']] = obj.gender
            res[fk_index['likeFruit']] = obj.likeFruit
            res[fk_index['userUrl']] = obj.userUrl
            res[fk_index['name']] = obj.name
            res[fk_index['desc']] = obj.desc
            res[fk_index['createTime']] = obj.createTime
            res[fk_index['lastTime']] = obj.lastTime
            res[fk_index['creator']] = obj.creator.username
            res[fk_index['editor']] = obj.editor.username
            data.append(res)
            # --------------------- #
        self.after_export(queryset, data, *args, **kwargs)
        return data

    class Meta:
        model = models.bossInfo
        skip_unchanged = True
        report_skipped = True
        fields = (
            "id", "age", "gender", "likeFruit", "userUrl", "name", "desc", "createTime", "lastTime", "creator",
            "editor")


@admin.register(models.bossInfo)
class bossInfoAdmin(ImportExportModelAdmin):
    fields = (
        "name", "age", "gender",
        "likeFruit", "userUrl", "desc")
    list_display = (
        "name", "age", "gender",
        "likeFruit", "userUrl",
        "createTime",
        "lastTime",
        "creator", "editor")
    list_display_links = ("name",)
    exclude = ("createTime", "creator", "editor")
    search_fields = ("name",)
    list_filter = ("gender", "likeFruit")
    model_icon = "fa fa-tag"
    list_per_page = 20
    ordering = ["-id"]
    resource_class = bossInfoResource

    def save_model(self, request, obj, form, change):
        if form.is_valid():
            if change:
                obj.editor = request.user
            else:
                obj.creator = request.user
                obj.editor = request.user
                obj.save()
        super().save_model(request, obj, form, change)

 

 Python Django 零基础破门而入篇(二)

 最终导出效果

Python Django 零基础破门而入篇(二)

 

6.导入配置

点击导入

提示都是字段名,用户肯定整不明白的

赶紧改成中文的   解决方法  

通过重写导入页面

 

Python Django 零基础破门而入篇(二)

7.在应用目录(app)下-->templatetags-->apptags.py

Python Django 零基础破门而入篇(二)

8.修改项目settings.py

Python Django 零基础破门而入篇(二)

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            'libraries': {
                'apptags': 'app.templatetags.apptags'
            },
        },
    },
]

9.重写django-import-export 导入页面

在项目templates下新建 admin-->import_export--> import.html 

import.html代码如下  将{{ fields|join:", " }}  替换成 apptags.py 定义的 import_head_tag 方法即可

找到项目中import_export 文件夹中 

Python Django 零基础破门而入篇(二)

 

10.在项目中的templates-->admin-->import_export 下把导入导出两个页面都复制过来(export.html   import.html)

Python Django 零基础破门而入篇(二)

11.修改import.html  标注背景色的两处

{% extends "admin/import_export/base.html" %}
{% load static simpletags apptags %}
{% load i18n %}
{% load admin_urls %}
{% load import_export_tags %}
{% load static %}

{% block extrastyle %}{{ block.super }}
    <link rel="stylesheet" type="text/css" href="{% static "import_export/import.css" %}"/>{% endblock %}

{% 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="submit-row">
                <input type="submit" class="default" name="confirm" value="{% trans "Confirm import" %}">
            </div>
        </form>
    {% else %}
        <form action="" method="post" enctype="multipart/form-data">
            {% csrf_token %}

            <p>
                {% trans "This importer will import the following fields: " %}
                {# <code>{{ fields|join:", " }}</code> #}
                <code>{% import_head_tag %}</code>
            </p>

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

                        {{ field.label_tag }}

                        {{ field }}

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

            <div class="submit-row">
                <input type="submit" class="default" value="{% trans "Submit" %}">
            </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">{{ 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">{{ error.traceback|linebreaks }}</div>
                        </li>
                    {% endfor %}
                {% endfor %}
            </ul>

        {% elif result.has_validation_errors %}

            <h2>{% trans "Some rows failed to validate" %}</h2>

            <p>{% trans "Please correct these errors in your data where possible, then reupload it using the form above." %}</p>

            <table class="import-preview">
                <thead>
                <tr>
                    <th>{% trans "Row" %}</th>
                    <th>{% trans "Errors" %}</th>
                    {% for field in result.diff_headers %}
                        <th>{{ field }}</th>
                    {% endfor %}
                </tr>
                </thead>
                <tbody>
                {% for row in result.invalid_rows %}
                    <tr>
                        <td>{{ row.number }} </td>
                        <td class="errors">
                            <span class="validation-error-count">{{ row.error_count }}</span>
                            <div class="validation-error-container">
                                <ul class="validation-error-list">
                                    {% for field_name, error_list in row.field_specific_errors.items %}
                                        <li>
                                            <span class="validation-error-field-label">{{ field_name }}</span>
                                            <ul>
                                                {% for error in error_list %}
                                                    <li>{{ error }}</li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endfor %}
                                    {% if row.non_field_specific_errors %}
                                        <li>
                                            <span class="validation-error-field-label">{% trans "Non field specific" %}</span>
                                            <ul>
                                                {% for error in row.non_field_specific_errors %}
                                                    <li>{{ error }}</li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endif %}
                                </ul>
                            </div>
                        </td>
                        {% for field in row.values %}
                            <td>{{ field }}</td>
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>
            </table>

        {% else %}

            <h2>{% trans "Preview" %}</h2>

            <table class="import-preview">
                <thead>
                <tr>
                    <th></th>
                    {% for field in result.diff_headers %}
                        <th>{{ field }}</th>
                    {% endfor %}
                </tr>
                </thead>
                {% for row in result.valid_rows %}
                    <tr class="{{ row.import_type }}">
                        <td class="import-type">
                            {% 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 %}

12.运行效果

导出包含创建时间,修改时间,创建者,修改者

Python Django 零基础破门而入篇(二)

导入 创建者修改者自动复制  选项值需要特殊处理例如多选Python Django 零基础破门而入篇(二)

Python Django 零基础破门而入篇(二)

Python Django 零基础破门而入篇(二)

 

13.自动将当前登录用户 赋值每条导入对象(instance)的 创建者/修改者字段  

 

导入效果

Python Django 零基础破门而入篇(二)

 

Python Django 零基础破门而入篇(二)

 

14.最终admin.py代码

import traceback
from copy import deepcopy

from django.contrib import admin
from django.core.exceptions import ValidationError
from django.db.transaction import TransactionManagementError
from django.utils.encoding import force_text
from import_export.results import RowResult

from app import models
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from django.apps import apps
from django.db.models import QuerySet
import tablib

# Register your models here.
admin.site.site_header = "大佬管理"
admin.site.site_title = "大佬管理后台管理"


class bossInfoResource(resources.ModelResource):

    def __init__(self):
        super(bossInfoResource, self).__init__()

        field_list = models.bossInfo._meta.fields
        self.vname_dict = {}
        self.fkey = []
        customeFields = (
            "id", "age", "gender", "likeFruit", "userUrl", "name", "desc",)
        for i in field_list:
            if i.name in customeFields:
                self.vname_dict[i.name] = i.verbose_name.lower()
                self.fkey.append(i.name)

    # 默认导入导出field的column_name为字段的名称,这里修改为字段的verbose_name
    def get_export_fields(self):
        fields = self.get_fields()
        for field in fields:
            field_name = self.get_field_name(field)
            # 如果我们设置过verbose_name,则将column_name替换为verbose_name。否则维持原有的字段名
            if field_name in self.vname_dict.keys():
                field.column_name = self.vname_dict[field_name]
        return fields

    def after_import(self, dataset, result, using_transactions, dry_run, **kwargs):
        print("after_import")

    def after_import_instance(self, instance, new, **kwargs):
        print("after_import_instance")

    # 重载resources.py的export方法,修改将要导出的data的某些外键相关数据。默认导出外键id,这里修改为导出外键对应的值
    def export(self, queryset=None, *args, **kwargs):
        self.before_export(queryset, *args, **kwargs)
        if queryset is None:
            queryset = self.get_queryset()
        headers = self.get_export_headers()
        headers.append("创建时间")
        headers.append("修改时间")
        headers.append("创建者")
        headers.append("修改者")
        data = tablib.Dataset(headers=headers)
        # 获取所有外键名称在headers中的位置
        fk_index = {}
        for fk in self.fkey:
            fk_index[fk] = headers.index(self.vname_dict[fk])
        # --------------------- #

        if isinstance(queryset, QuerySet):
            # Iterate without the queryset cache, to avoid wasting memory when
            # exporting large datasets.
            iterable = queryset.iterator()
        else:
            iterable = queryset
        for obj in iterable:
            # --------------------- #
            # 获取将要导出的源数据,这里export_resource返回的是列表,便于更改。替换到外键的值
            # 可以对所有字段值进行二次处理
            res = self.export_resource(obj)
            res[fk_index['id']] = obj.id
            res[fk_index['age']] = obj.age
            res[fk_index['gender']] = obj.gender
            res[fk_index['likeFruit']] = obj.likeFruit
            res[fk_index['userUrl']] = obj.userUrl
            res[fk_index['name']] = obj.name
            res[fk_index['desc']] = obj.desc
            res.append(obj.createTime)
            res.append(obj.lastTime)
            res.append(obj.creator.username)
            res.append(obj.editor.username)
            data.append(res)
            # --------------------- #
        self.after_export(queryset, data, *args, **kwargs)
        return data

    # 导入前
    def before_import_row(self, row, **kwargs):
        print(row)

    # 导入后(执行更新创建者修改)
    def after_import_row(self, row, row_result, **kwargs):
        print(row)

    # 导入数据 自动将当前登录用户 赋值给创建者和修改者
    def import_row(self, row, instance_loader, using_transactions=True, dry_run=False, **kwargs):
        print(instance_loader)
        row_result = self.get_row_result_class()()
        try:
            self.before_import_row(row, **kwargs)
            instance, new = self.get_or_init_instance(instance_loader, row)
            self.after_import_instance(instance, new, **kwargs)
            if new:
                row_result.import_type = RowResult.IMPORT_TYPE_NEW
            else:
                row_result.import_type = RowResult.IMPORT_TYPE_UPDATE
            row_result.new_record = new
            original = deepcopy(instance)
            diff = self.get_diff_class()(self, original, new)
            if self.for_delete(row, instance):
                if new:
                    row_result.import_type = RowResult.IMPORT_TYPE_SKIP
                    diff.compare_with(self, None, dry_run)
                else:
                    row_result.import_type = RowResult.IMPORT_TYPE_DELETE
                    self.delete_instance(instance, using_transactions, dry_run)
                    diff.compare_with(self, None, dry_run)
            else:
                import_validation_errors = {}
                try:
                    self.import_obj(instance, row, dry_run)
                except ValidationError as e:
                    # Validation errors from import_obj() are passed on to
                    # validate_instance(), where they can be combined with model
                    # instance validation errors if necessary
                    import_validation_errors = e.update_error_dict(import_validation_errors)
                if self.skip_row(instance, original):
                    row_result.import_type = RowResult.IMPORT_TYPE_SKIP
                else:
                    self.validate_instance(instance, import_validation_errors)
                    print(instance)
                    print("dry_run", dry_run)
                    if instance.creator is None:
                        instance.creator = kwargs["user"]
                    instance.editor = kwargs["user"]
                    self.save_instance(instance, using_transactions, dry_run)
                    self.save_m2m(instance, row, using_transactions, dry_run)
                    # Add object info to RowResult for LogEntry
                    row_result.object_id = instance.pk
                    row_result.object_repr = force_text(instance)
                diff.compare_with(self, instance, dry_run)

            row_result.diff = diff.as_html()
            self.after_import_row(row, row_result, **kwargs)

        except ValidationError as e:
            row_result.import_type = RowResult.IMPORT_TYPE_INVALID
            row_result.validation_error = e
        except Exception as e:
            row_result.import_type = RowResult.IMPORT_TYPE_ERROR
            # There is no point logging a transaction error for each row
            # when only the original error is likely to be relevant
            if not isinstance(e, TransactionManagementError):
                print(e)
            tb_info = traceback.format_exc()
            row_result.errors.append(self.get_error_result_class()(e, tb_info, row))
        return row_result

    class Meta:
        model = models.bossInfo
        skip_unchanged = True
        report_skipped = True
        fields = (
            "id", "age", "gender", "likeFruit", "userUrl", "name", "desc",)


@admin.register(models.bossInfo)
class bossInfoAdmin(ImportExportModelAdmin):
    fields = (
        "name", "age", "gender",
        "likeFruit", "userUrl", "desc")
    list_display = (
        "name", "age", "gender",
        "likeFruit", "userUrl",
        "createTime",
        "lastTime",
        "creator", "editor")
    list_display_links = ("name",)
    exclude = ("createTime", "creator", "editor")
    search_fields = ("name",)
    list_filter = ("gender", "likeFruit")
    model_icon = "fa fa-tag"
    list_per_page = 20
    ordering = ["-id"]
    resource_class = bossInfoResource

    def save_model(self, request, obj, form, change):
        if form.is_valid():
            if change:
                obj.editor = request.user
            else:
                obj.creator = request.user
                obj.editor = request.user
                obj.save()
        super().save_model(request, obj, form, change)

 

15.给导入导出页面 (export.html    import.html) 新增返回按钮

{% extends "admin/import_export/base.html" %}
{% load static simpletags apptags %}
{% load i18n %}
{% load admin_urls %}
{% load import_export_tags %}
{% load static %}

{% block extrastyle %}{{ block.super }}
    <link rel="stylesheet" type="text/css" href="{% static "import_export/import.css" %}"/>{% endblock %}

{% 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="submit-row">
                <input type="submit" class="default" name="confirm" value="{% trans "Confirm import" %}">
            </div>
        </form>
    {% else %}
        <form action="" method="post" enctype="multipart/form-data">
            {% csrf_token %}

            <p>
                {% trans "This importer will import the following fields: " %}
                {# <code>{{ fields|join:", " }}</code> #}
                <code>{% import_head_tag %}</code>
            </p>

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

                        {{ field.label_tag }}

                        {{ field }}

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

            <div class="submit-row">
                <input type="button" class="el-button el-button--default is-plain" style="float: left"
                       onclick="javascript:window.history.go(-1)" value="返回"/>
                <input type="submit" class="default" value="{% trans "Submit" %}">
            </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">{{ 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">{{ error.traceback|linebreaks }}</div>
                        </li>
                    {% endfor %}
                {% endfor %}
            </ul>

        {% elif result.has_validation_errors %}

            <h2>{% trans "Some rows failed to validate" %}</h2>

            <p>{% trans "Please correct these errors in your data where possible, then reupload it using the form above." %}</p>

            <table class="import-preview">
                <thead>
                <tr>
                    <th>{% trans "Row" %}</th>
                    <th>{% trans "Errors" %}</th>
                    {% for field in result.diff_headers %}
                        <th>{{ field }}</th>
                    {% endfor %}
                </tr>
                </thead>
                <tbody>
                {% for row in result.invalid_rows %}
                    <tr>
                        <td>{{ row.number }} </td>
                        <td class="errors">
                            <span class="validation-error-count">{{ row.error_count }}</span>
                            <div class="validation-error-container">
                                <ul class="validation-error-list">
                                    {% for field_name, error_list in row.field_specific_errors.items %}
                                        <li>
                                            <span class="validation-error-field-label">{{ field_name }}</span>
                                            <ul>
                                                {% for error in error_list %}
                                                    <li>{{ error }}</li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endfor %}
                                    {% if row.non_field_specific_errors %}
                                        <li>
                                            <span class="validation-error-field-label">{% trans "Non field specific" %}</span>
                                            <ul>
                                                {% for error in row.non_field_specific_errors %}
                                                    <li>{{ error }}</li>
                                                {% endfor %}
                                            </ul>
                                        </li>
                                    {% endif %}
                                </ul>
                            </div>
                        </td>
                        {% for field in row.values %}
                            <td>{{ field }}</td>
                        {% endfor %}
                    </tr>
                {% endfor %}
                </tbody>
            </table>

        {% else %}

            <h2>{% trans "Preview" %}</h2>

            <table class="import-preview">
                <thead>
                <tr>
                    <th></th>
                    {% for field in result.diff_headers %}
                        <th>{{ field }}</th>
                    {% endfor %}
                </tr>
                </thead>
                {% for row in result.valid_rows %}
                    <tr class="{{ row.import_type }}">
                        <td class="import-type">
                            {% 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 %}

 

14.项目运行安装包版本

需要留意tablib 库版本

Python Django 零基础破门而入篇(二)

相关文章: