【问题标题】:django: export current queryset to csv by button click in browserdjango:通过在浏览器中单击按钮将当前查询集导出到 csv
【发布时间】:2015-04-16 10:50:14
【问题描述】:

专家您好! 能否请你帮忙。 我很少有返回不同查询集的视图。 我的目标是在用户单击浏览器中的按钮时将当前查询集导出到 csv。

您能否推荐一下执行此操作的最佳算法是什么? 仅当在浏览器中单击按钮时,我已经完成了将查询保存到 csv 的所有操作。

提前谢谢你!

【问题讨论】:

  • 最好的算法,总是比较的。您能否告诉我们您的尝试,以便我们向您提出建议,并加以改进?
  • 您可能首先需要一个将查询集作为输入的表单,然后在视图中执行 csv 业务。创建文件后,您可以通过显示 csv 文件的 url 将其提供给用户

标签: django


【解决方案1】:

在你看来

import csv
.....
output = []
response = HttpResponse (content_type='text/csv')
writer = csv.writer(response)
query_set = User.objects.select_related('profile').all()
#Header
writer.writerow(['First Name', 'Last Name', 'Full Name', 'Short Name'])
for user in query_set:
    output.append([user.first_name, user.last_name, user.get_full_name, user.profile.short_name])
#CSV Data
writer.writerows(output)
return response

这很好用

【讨论】:

    【解决方案2】:

    如果您使用基于分类的视图,它真的很容易(这是他们最擅长的任务)。子类化主视图,覆盖模板和内容类型。

    这是我的一个项目中的一个示例

    views.py

    class SavedSamplesView(ListView):
        """
        This is the standard view returning HTML
        """
        template_name = "SavedSamples.html"
        model = Sample 
        context_object_name = "sample_list"
    
        def get_queryset(self) :
            slug =  self.kwargs['submission_slug']
            return Sample.objects.filter(submission__submission_slug=slug)
    
    class SavedSamplesCsvView(SavedSamplesView):
        """
        Subclass of above view, to produce a csv file
        """
        template_name = 'SavedSamples.csv'
        content_type = 'text/csv'
    

    模板 SavedSamples.cvs 看起来像这样(获取换行符的格式有点难看,但它可以工作)。第一行是标题,如果不需要,请删除它:

    sample.id , sample.name , ... , comments
    {% for sample in sample_list %}{{ sample.id }},{{ sample.name }},....,{{sample.comments}}
    {% endfor %}
    

    urls.py

    url(r'^savedsamplescsv/(?P<submission_slug>[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\-_]+)/', views.SavedSamplesCsvView.as_view(),  name='saved_samples_csv'),
    

    我会使用链接而不是按钮,并将其设置为按钮。

    【讨论】:

    • urls.py 中,您还可以使用更短的正则表达式:url(r'^savedsamplescsv/(?P&lt;submission_slug&gt;[A-Za-z0-9\-_]+)/$', views.SavedSamplesCsvView.as_view(), name='saved_samples_csv'),(是的,我在正则表达式末尾添加了$ 字符)
    • 是的。我想我这样做可能是有原因的,但现在想不起来了。
    • 更pythonic:“显式优于隐式。” 大多数时候:P
    • 其实我更喜欢你的版本,这在我看来更隐含(必须是我的 Perl 背景)。但是目前的那个已经在生产中工作了一段时间,所以没有理由潜在地引入问题。
    【解决方案3】:

    我使用以下 sn-p 为我的查询集生成 CSV。它还包括相关字段,您可以选择忽略或使用其他内容来序列化数据。 (比如Django自带的默认序列化器)

    import csv
    
    
    def dump_to_csv(model, qs):
        """
        Takes in a Django queryset and spits out a CSV file.
        """
    
        model = qs.model
        writer = ''
    
        headers = []
    
        # Get standard fields
        for field in model._meta.get_fields():
            headers.append(field) if 'extra' not in field.name else None
    
        writer += ','.join([field.name for field in headers])
        writer += '\n'
    
        for obj in qs:
            row = []
            for field in headers:
                # Append all general fields
                if field.get_internal_type() not in ['ForeignKey', 'ManyToManyField', 'OneToOneField']:
                    val = getattr(obj, field.name)
                    if callable(val):
                        val = val()
                    if type(val) == str:
                        val = val.encode("utf-8")
                    row.append(str(val))
    
                # Append all fk fields
                elif field.get_internal_type() in ['ForeignKey', 'OneToOneField']:
                    from django.core import serializers
                    import json
    
                    value = field.value_from_object(obj)
    
                    if value not in [None, ""]:
                        qs = field.remote_field.model.objects.filter(pk=value)
                        json_data = serializers.serialize("json", qs, fields=(field.name for field
                                                                              in qs.first()._meta.get_fields() if
                                                                              'extra' not in field.name))
                        json_data = [o['fields'] for o in json.loads(json_data)]
                        json_data = json.dumps(json_data)
                        json_data = json_data.replace(",", ";")
                        json_data = json_data.replace("\"", "'")
                        row.append(json_data)
                    else:
                        row.append("[]")
    
                # Append all m2m fields
                elif field.get_internal_type() in ['ManyToManyField']:
                    from django.core import serializers
                    import json
    
                    qs = getattr(obj, field.name).all()
                    json_data = serializers.serialize("json", qs)
                    json_data = [o['fields'] for o in json.loads(json_data)]
                    json_data = json.dumps(json_data)
                    json_data = json_data.replace(",", ";")
                    json_data = json_data.replace("\"", "'")
                    row.append(json_data)
    
            writer += ','.join(row)
            writer += '\n'
    
        return writer
    

    我有这个的原因是因为我的用例要求我也有每个相关对象的 JSON 转储。

    然后你可以在响应中返回这个:

    file = dump_to_csv(qs.model, qs)
    
                response = HttpResponse(file, content_type='text/csv')
                response['Content-Disposition'] = u'attachment; filename="{0}"'.format('export.csv')
                return response
    

    【讨论】:

      猜你喜欢
      • 2016-01-25
      • 1970-01-01
      • 2012-08-24
      • 1970-01-01
      • 1970-01-01
      • 2020-05-12
      • 2019-05-09
      • 2019-07-26
      • 1970-01-01
      相关资源
      最近更新 更多