导出 Haystack 搜索结果

Export Haystack search results

我正在尝试导出用户搜索的结果。我正在使用 Django + Haystack + Solr 来生成搜索结果。目前,为了创建 SearchQuerySet 来写出 CSV,我将查询参数从搜索结果页面传递到生成 CSV 的视图并在那里重建 SearchQuerySet。这真的很痛苦,因为搜索非常复杂,有多个方面、多个模型等,而且当我对 SearchForm 进行修改时,经常会出现错误。似乎应该有一种简单的方法可以将结果直接传递给导出视图。有什么建议吗?

编辑

我想出了自己的解决方案,并将所有修改的代码放在答案中。请看下面。希望这可以防止其他人用头撞墙一周!

好吧,我终于自己弄明白了。我基本上必须为我的 SearchForm 添加第二个提交按钮到 html,然后使用 javascript 将操作重定向到我的 "search_export" 视图。由于在提交表单时不会传递构面,因此我必须从请求中获取构面(在搜索页面模板中)并将它们传递给通过 url 进行查看。然后必须在视图中重新评估这些方面。我将在下面粘贴我的所有代码:

search.html

{% block content %}

    <form method="get" action=".">

        <!-- Advanced Search Box -->
        <div class="row">
            <div class="col-lg-12">
                <h2 class="text-center">Advanced Search</h2>

                <!-- Search Form Fields Here -->

                <ul class="list-inline center-block text-center adv-form">
                    <li>
                        <p><input type="submit" value="Search"></p>
                    </li>
                    <li>
                        <p><input type="submit" id="export" value="Export Results"></p>
                    </li>                            
                </ul>
            </div>
        </div>
        <!-- End Advanced Search Box -->

        <!-- Search Results are displayed here -->

{% endblock %}

<!-- Search Unique JS -->
{% block js %}

{{ block.super }}

  <script>
    $(document).ready(function () {

        $("#export").click(function() {
          $(this).closest("form").attr('action', "{% query_params_getlist request 'selected_facets' as facets %}{% url 'search_export' facets %}");
        });

    });
  </script>

{% endblock %}
<!-- End Search Unique JS -->

urls.py

urlpatterns = patterns('base.views',
    # all the other url patterns go here
    url(r'^search_export/(?P<selected_facets>\S+)/$', 'search_export', name='search_export'),    
)

base_tags.py

@register.assignment_tag
def query_params_getlist(request, param):
    params = request.GET.getlist(param)
    if len(params) > 0:
        query_string = ""
        for p in params:
            query_string += p + '&'
        return query_string
    return 'None'

views.py

def search_export(request, selected_facets):
    if request.method == 'GET':
        form = AdvModelSearchForm(request.GET)
        if form.is_valid():
                qs = form.search()

                #deal with facets
                facets = selected_facets.split("&")

                for facet in facets:
                    if ":" not in facet:
                        continue

                    field, value = facet.split(":", 1)

                    if value:
                        # faceted fields are stored in a hierarchy, so I check for any document with the given facet or its children
                        control_value = ControlField.objects.filter(pk=qs.query.clean(value))
                        if control_value:
                            value_tree = control_value[0].get_descendants(include_self=True)
                            sq = SQ()
                            for index, node in enumerate(value_tree):
                                kwargs = {str("%s" % (field)) : str("%s" % (node.id))}
                                if index == 0:
                                    sq = SQ(**kwargs)
                                else:
                                    sq = sq | SQ(**kwargs)
                            qs = qs.filter(sq)                

                response = HttpResponse(content_type='text/csv')
                response['Content-Disposition'] = 'attachment; filename="search_results.csv"'

                writer = csv.writer(response)
                titles = []
                rows = []
                for result in qs:
                    row = []
                    row_dict = {}
                    properties = result.text #IMPT - this field must be a MultiValueField in the Haystack search_indexes.py file or this won't return a list
                    for each_prop in properties:
                        prop_pair = each_prop.split(':', 1)
                        if len(prop_pair) < 2:
                            continue
                        prop_name = smart_str(prop_pair[0].strip())
                        prop_value = smart_str(prop_pair[1].strip())
                        if not (prop_name in titles):
                            column_index = len(titles)                        
                            titles.append(prop_name)
                        else:
                            column_index = titles.index(prop_name)
                            if column_index in row_dict:
                                prop_value = row_dict[column_index] + '; ' + prop_value
                        row_dict[column_index] = prop_value
                    for i in range(len(titles)):
                        if i in row_dict:
                            row.append(row_dict[i])
                        else:
                            row.append('')
                    rows.append(row)

                writer.writerow(titles)
                for each_row in rows:
                    writer.writerow(each_row)
                return response

    return HttpResponseRedirect('/failed_export/')