【问题标题】:Generating CSV file with Django (dynamic content)使用 Django 生成 CSV 文件(动态内容)
【发布时间】:2011-05-03 14:55:35
【问题描述】:

在我的 view.py 中,我有两个函数,一个处理来自表单的输入并输出过滤列表,另一个应该将此列表导出为 CSV。

这是我的第一个函数的返回:

return render_to_response('templateX.html',
{
 'queryset': queryset,
 'filter_form': filter_form,
 'validated': validated,
},
 context_instance = RequestContext(request)
 )

这里是导出函数:

def export_to_csv(request):
    # get the response object, this can be used as a stream.
    response = HttpResponse(mimetype='text/csv')
    # force download.
    response['Content-Disposition'] = 'attachment;filename=export.csv'
    # the csv writer
    writer = csv.writer(response)
    qs = request.session['queryset']
    for cdr in qs:
        writer.writerow([cdr['calldate'], cdr['src'], cdr['dst'], ])
    return response   

我不确定如何从我的第一个函数中获取 queryset,其中包含我想要在我的 CSV 中的项目列表并在我的 export_to_csv 函数中使用它。 或者最好的方法是将这两个功能结合起来,让用户点击一个复选框,无论他/她是否想要下载 CSV 文件。 任何帮助将不胜感激。

【问题讨论】:

    标签: python django csv


    【解决方案1】:

    我建议将它们组合成一个带有额外参数的视图函数:

    def my_view(request, exportCSV):
        # ... Figure out `queryset` here ...
    
        if exportCSV:
            response = HttpResponse(mimetype='text/csv')
            response['Content-Disposition'] = 'attachment;filename=export.csv'
            writer = csv.writer(response)
            for cdr in queryset:
                writer.writerow([cdr['calldate'], cdr['src'], cdr['dst'], ])
            return response
        else:
            return render_to_response('templateX.html', {'queryset': queryset,
                'filter_form': filter_form, 'validated': validated},
                context_instance = RequestContext(request))
    

    然后,在您的urls.py 中,在您的urlpatterns 中添加类似这样的内容:

    url(r'^form', 'my_view', {"exportCSV": False}, name="form"),
    url(r'^csv', 'my_view', {"exportCSV": True}, name="export"),
    

    【讨论】:

    • 我试过这种方式,但是当我点击我的“导出”按钮时,它会转到 url:localhost:8000/cdr/export_csv,它会丢失所有的 GET 请求,结果是没有处理查询集,所以我的 CSV 文件是空的。那么我的“导出”按钮如何像点击“搜索”按钮一样发送所有请求?
    • 您的“导出”按钮应该 1) 以导出 URL 为目标并包含查询参数,或者 2) 作为具有查询参数的表单的一部分,如有必要,作为隐藏字段。我很难提出具体的建议,因为我并不完全清楚您的网页之间的关系。
    • 是的,我决定按照您描述的第一选择的方式进行操作。现在是“隐藏字段”,这很有趣,稍后我会在遇到类似情况时再看。
    • 隐藏字段为<input type="hidden" name="foo" value="bar" />。我不知道 Django 是否有一些特殊的魔法来生成它们,但它们很容易自己生成。请记住,即使表单参数来自隐藏字段,也不要隐含地信任它。验证它。
    • mimetype 应该是 content_type。现在改了
    【解决方案2】:

    恕我直言,最好的办法是将它们组合起来并从显式查询集中生成 CSV 数据。然后可以将其重写为一般的内容,例如(未测试):

    def export_to_csv(request, queryset, fields):
        response = ...
        writer = csv.writer(response)
        for obj in queryset:
            writer.writerow([getattr(obj, f) for f in fields])
        return response
    

    你可以这样使用:

    def my_view(request):
        calls = Call.objects.all()
        return export_to_csv(request, calls, fields = ('calldate', 'src', 'dst'))
    

    --

    您提供的示例代码假定 QuerySet 是在会话数据中设置的,这可能会给您带来大量错误和安全问题。如果您将会话存储在数据库中,您最终可能会读取数据,只是以效率低得多的形式将其写回。

    【讨论】:

      【解决方案3】:

      我找到了一种不同于 knutin 的方法。 我在函数或全局变量之外声明了一个名为 csv_list = [] 的空列表。

      在我的主要功能(根据用户输入处理和过滤的功能)中,我将此 csv_list 设为全局,以便将其设置为查询集的“更新”版本。 然后生成 csv,很简单: 在 csv_list 中调用: writer.writerow([call.src, call.dst]) 返回响应

      现在工作正常。

      【讨论】:

      • 使用全局变量通过视图传递数据是危险的; Django 可以线程化,这可能会在部署时中断。您自己测试时不会看到此错误,并且由于它基于竞争条件,因此很难追踪它。
      • 您能否详细说明危险性以及它在部署时可能会如何中断?
      • 用户 1 发布了对您的表单的请求。这将调用设置csv_list 的视图函数。用户 2 做同样的事情,再次设置csv_list。然后,用户 1 导出 CSV,并改为通过 csv_list 获取用户 2 的数据。
      • 好的,知道了。这是灾难性的。
      【解决方案4】:

      以下内容接受一个 Django 查询集并输出一个 CSV 文件。

      用法::

      从实用程序导入 dump2csv

      从 dummy_app.models 导入 *

      qs = DummyModel.objects.all()

      dump2csv.dump(qs, './data/dump.csv')

      脚本:

      import csv
      from django.db.models.loading import get_model
      
      def dump(qs, outfile_path):
      
          model = qs.model
      writer = csv.writer(open(outfile_path, 'w'))
      
      headers = []
      for field in model._meta.fields:
          headers.append(field.name)
      writer.writerow(headers)
      
      for obj in qs:
          row = []
          for field in headers:
              val = getattr(obj, field)
              if callable(val):
                  val = val()
              if type(val) == unicode:
                  val = val.encode("utf-8")
              row.append(val)
          writer.writerow(row)
      

      【讨论】:

        猜你喜欢
        • 2021-08-21
        • 1970-01-01
        • 2018-11-18
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 1970-01-01
        • 2011-04-21
        • 1970-01-01
        相关资源
        最近更新 更多