ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python – 将django-import-export与基于类的视图一起使用

2019-07-22 20:58:34  阅读:55  来源: 互联网

标签:django-class-based-views python django django-views


我想将django-import-export与基于类的视图一起使用.

https://django-import-export.readthedocs.org/en/latest/getting_started.html的文档中,我看到了一个导出为csv的示例

>>> dataset = BookResource().export()
>>> print dataset.csv
id,name,author,author_email,imported,published,price,categories
2,Some book,1,,0,2012-12-05,8.85,1

但如果我想返回一个Excel文件,我应该使用哪个基于类的视图?只是查看?

解决方法:

Jamgreen,

基于https://github.com/bmihelac/django-import-export的实现并将模型“Country”视为具有名称和abreviation属性的示例:

首先,在Country模型的末尾定义资源:

class CountryResource(resources.ModelResource):
    class Meta:
        model = Country

然后,实现基于类的视图:

class CountryExport(View):

    def get(self, *args, **kwargs ):
        dataset = CountryResource().export()
        response = HttpResponse(dataset.csv, content_type="csv")
        response['Content-Disposition'] = 'attachment; filename=filename.csv'
        return response


class CountryImport(View):
    model = Country
    from_encoding = "utf-8"

    #: import / export formats
    DEFAULT_FORMATS = (
        base_formats.CSV,
        base_formats.XLS,
        base_formats.TSV,
        base_formats.ODS,
        base_formats.JSON,
        base_formats.YAML,
        base_formats.HTML,
    )
    formats = DEFAULT_FORMATS
    #: template for import view
    import_template_name = 'Country/import.html'
    resource_class = None

    def get_import_formats(self):
        """
        Returns available import formats.
        """
        return [f for f in self.formats if f().can_import()]

    def get_resource_class(self):
        if not self.resource_class:
            return modelresource_factory(self.model)
        else:
            return self.resource_class

    def get_import_resource_class(self):
        """
        Returns ResourceClass to use for import.
        """
        return self.get_resource_class()

    def get(self, *args, **kwargs ):
        '''
        Perform a dry_run of the import to make sure the import will not
        result in errors.  If there where no error, save the user
        uploaded file to a local temp file that will be used by
        'process_import' for the actual import.
        '''
        resource = self.get_import_resource_class()()

        context = {}

        import_formats = self.get_import_formats()
        form = ImportForm(import_formats,
                          self.request.POST or None,
                          self.request.FILES or None)

        if self.request.POST and form.is_valid():
            input_format = import_formats[
                int(form.cleaned_data['input_format'])
            ]()
            import_file = form.cleaned_data['import_file']
            # first always write the uploaded file to disk as it may be a
            # memory file or else based on settings upload handlers
            with tempfile.NamedTemporaryFile(delete=False) as uploaded_file:
                for chunk in import_file.chunks():
                    uploaded_file.write(chunk)

            # then read the file, using the proper format-specific mode
            with open(uploaded_file.name,
                      input_format.get_read_mode()) as uploaded_import_file:
                # warning, big files may exceed memory
                data = uploaded_import_file.read()
                if not input_format.is_binary() and self.from_encoding:
                    data = force_text(data, self.from_encoding)
                dataset = input_format.create_dataset(data)
                result = resource.import_data(dataset, dry_run=True,
                                              raise_errors=False)

            context['result'] = result

            if not result.has_errors():
                context['confirm_form'] = ConfirmImportForm(initial={
                    'import_file_name': os.path.basename(uploaded_file.name),
                    'input_format': form.cleaned_data['input_format'],
                })

        context['form'] = form
        context['opts'] = self.model._meta
        context['fields'] = [f.column_name for f in resource.get_fields()]

        return TemplateResponse(self.request, [self.import_template_name], context)


    def post(self, *args, **kwargs ):
        '''
        Perform a dry_run of the import to make sure the import will not
        result in errors.  If there where no error, save the user
        uploaded file to a local temp file that will be used by
        'process_import' for the actual import.
        '''
        resource = self.get_import_resource_class()()

        context = {}

        import_formats = self.get_import_formats()
        form = ImportForm(import_formats,
                          self.request.POST or None,
                          self.request.FILES or None)

        if self.request.POST and form.is_valid():
            input_format = import_formats[
                int(form.cleaned_data['input_format'])
            ]()
            import_file = form.cleaned_data['import_file']
            # first always write the uploaded file to disk as it may be a
            # memory file or else based on settings upload handlers
            with tempfile.NamedTemporaryFile(delete=False) as uploaded_file:
                for chunk in import_file.chunks():
                    uploaded_file.write(chunk)

            # then read the file, using the proper format-specific mode
            with open(uploaded_file.name,
                      input_format.get_read_mode()) as uploaded_import_file:
                # warning, big files may exceed memory
                data = uploaded_import_file.read()
                if not input_format.is_binary() and self.from_encoding:
                    data = force_text(data, self.from_encoding)
                dataset = input_format.create_dataset(data)
                result = resource.import_data(dataset, dry_run=True,
                                              raise_errors=False)

            context['result'] = result

            if not result.has_errors():
                context['confirm_form'] = ConfirmImportForm(initial={
                    'import_file_name': os.path.basename(uploaded_file.name),
                    'input_format': form.cleaned_data['input_format'],
                })

        context['form'] = form
        context['opts'] = self.model._meta
        context['fields'] = [f.column_name for f in resource.get_fields()]

        return TemplateResponse(self.request, [self.import_template_name], context)

class CountryProcessImport(View):
    model = Country
    from_encoding = "utf-8"

    #: import / export formats
    DEFAULT_FORMATS = (
        base_formats.CSV,
        base_formats.XLS,
        base_formats.TSV,
        base_formats.ODS,
        base_formats.JSON,
        base_formats.YAML,
        base_formats.HTML,
    )
    formats = DEFAULT_FORMATS
    #: template for import view
    import_template_name = 'Country/import.html'
    resource_class = None



    def get_import_formats(self):
        """
        Returns available import formats.
        """
        return [f for f in self.formats if f().can_import()]

    def get_resource_class(self):
        if not self.resource_class:
            return modelresource_factory(self.model)
        else:
            return self.resource_class

    def get_import_resource_class(self):
        """
        Returns ResourceClass to use for import.
        """
        return self.get_resource_class()

    def post(self, *args, **kwargs ):
        '''
        Perform the actual import action (after the user has confirmed he
    wishes to import)
        '''
        opts = self.model._meta
        resource = self.get_import_resource_class()()

        confirm_form = ConfirmImportForm(self.request.POST)
        if confirm_form.is_valid():
            import_formats = self.get_import_formats()
            input_format = import_formats[
                int(confirm_form.cleaned_data['input_format'])
            ]()
            import_file_name = os.path.join(
                tempfile.gettempdir(),
                confirm_form.cleaned_data['import_file_name']
            )
            import_file = open(import_file_name, input_format.get_read_mode())
            data = import_file.read()
            if not input_format.is_binary() and self.from_encoding:
                data = force_text(data, self.from_encoding)
            dataset = input_format.create_dataset(data)

            result = resource.import_data(dataset, dry_run=False,
                                 raise_errors=True)

            # Add imported objects to LogEntry
            ADDITION = 1
            CHANGE = 2
            DELETION = 3
            logentry_map = {
                RowResult.IMPORT_TYPE_NEW: ADDITION,
                RowResult.IMPORT_TYPE_UPDATE: CHANGE,
                RowResult.IMPORT_TYPE_DELETE: DELETION,
            }
            content_type_id=ContentType.objects.get_for_model(self.model).pk
            '''
            for row in result:
                LogEntry.objects.log_action(
                    user_id=request.user.pk,
                    content_type_id=content_type_id,
                    object_id=row.object_id,
                    object_repr=row.object_repr,
                    action_flag=logentry_map[row.import_type],
                    change_message="%s through import_export" % row.import_type,
                )
            '''
            success_message = _('Import finished')
            messages.success(self.request, success_message)
            import_file.close()

            url = reverse('%s_list' % (str(opts.app_label).lower()))
            return HttpResponseRedirect(url)

模板import.html具有以下代码:

<h1>{% trans "Importar" %} {{ opts.app_label }}</h1>

{% if confirm_form %}
  <form action="{% url "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="btn" name="confirm" value="{% trans "Confirm import" %}">
    </div>
  </form>

{% else %}
  <form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form" enctype="multipart/form-data">
    {% csrf_token %}

    <p>
      {% trans "This importer will import the following fields: " %}
      {% for f in fields  %}
        {% if forloop.counter0 %}
        , 
        {% endif %}
        <tt>{{ f }}</tt>
      {% endfor %}
    </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="btn" 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 }}</li>
            {% endfor %}
            {% for line, errors in result.row_errors %}
                {% for error in errors %}
                    <li>
                      {% trans "Line number" %}: {{ line }} - {{ error.error }}
                      <div class="traceback">{{ error.traceback|linebreaks }}</div>
                    </li>
                {% endfor %}
            {% endfor %}
        </ul>
    {% else %}
        <h2>
            {% trans "Preview" %}
        </h2>
        <table>
        <thead>
          <tr>
            <th></th>
            {% for field in fields %}
              <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 %}

并且urls.py应包含:

#export
url(r'export/$', login_required(CountryExport.as_view()), name='country_export'),

#import
url(r'import/$', login_required(CountryImport.as_view()), name='country_import'),
url(r'process_import/$',     login_required(CountryProcessImport.as_view()), name='process_import'),

标签:django-class-based-views,python,django,django-views
来源: https://codeday.me/bug/20190722/1506746.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有