【问题标题】:Export data from a form从表单导出数据
【发布时间】:2015-05-30 06:18:44
【问题描述】:

我需要用户输入一些日期才能使用这些日期查询数据库,所以我按照these 的步骤操作,现在可以正常工作。我想要的是,除了显示响应中的数据之外,还能够将该数据导出到文件中。为此,我制作了一个表格,但我不知道如何继续。

我的问题是,我在哪里可以查阅有关如何从表单导出的文档?

观看次数

from django.shortcuts import render
from .forms import ContactForm

def filter_contracts(request):
    form = ContractForm(request.POST or None)
    contracts = None

    if request.method == 'POST':
        if form.is_valid():
                contracts = Contract.objects.filter(person__is_doctor=False,
                type_contract=Contract.FC,
                starting_date__gte=form.cleaned_data.get('starting_date'),
                ending_date__lte=form.cleaned_data.get('ending_date'))

    return render(request, 'your_template.html', {'form': form,
        'contracts': contracts})

表格

class ContractForm(forms.Form):

    starting_date    = forms.DateField()
    ending_date       = forms.DateField()

模板

{% extends "admin/base_site.html" %}
{% load i18n admin_urls admin_static admin_modify %}

{% block content %}
<form action="." enctype="db_personal/x-www-form-urlencoded" method="POST">>
    <ul>
        {{ form.as_ul }}
    </ul>
    {% csrf_token %}
    <button type="submit">Search</button>
    <br> 
    <hr>
    {% if contracts %}
    <table border ="1" cellspacing="0">
        <th>Person</th>
        <th>Contract type</th>
        <th>Starting date</th>
        <th>Ending date</th>
        {% for contract in contracts %}
        <tr>
            <td>{{ contract.person }}</td>
            <td>{{ contract.type_contract }}</td>
            <td>{{ contract.starting_date }}</td>
            <td>{{ contract.ending_date }}</td>
        </tr>
        {% endfor %}
    </table>
    {% endif %}
</form>
{% endblock %}

【问题讨论】:

  • 请说明您打算做什么。如果视图中的代码可以访问用户输入的表单数据,那么只需将其保存到文件中...
  • @Pynchia 关键是如何使用带有类似this 的按钮的按钮加入我的view

标签: django django-forms django-admin


【解决方案1】:

如果您想以 HTML 以外的形式返回查询集结果,只需让您的视图以您选择的适当格式返回数据 - 这可以是 csv、xml、json、yaml 或纯文本。

请参阅 Django 文档中有关如何导出 csv 数据的示例:

Django 文档也有一个如何导出 PDF 的页面:

在您看来——在处理表单并查询数据库之后——您应该设置响应的内容类型,以便浏览器知道它期望的数据类型。您的格式化数据将进入响应正文。大多数浏览器只能显示 HTML 或纯文本,可能还有 XML,但其他任何内容都只会作为文件下载到用户的计算机。

处理“下载”按钮的示例代码

第 1 步

在您的forms.py 中,添加一个额外的表单来处理“下载”按钮:

from django import forms

class ContractForm(forms.Form):
    starting_date    = forms.DateField()
    ending_date       = forms.DateField()

class DownloadForm(forms.Form):
    starting_date = forms.CharField(widget=forms.HiddenInput)
    ending_date = forms.CharField(widget=forms.HiddenInput)

此表单包含 2 个隐藏字段——starting_dateending_date。我们将根据初始搜索查询参数填充这些字段。

第 2 步

在您的views.py 中,添加代码以呈现DownloadForm(作为按钮):

from django.shortcuts import render
from .forms import ContractForm, DownloadForm

def filter_contracts(request):
    form = ContractForm(request.POST or None)
    contracts = None
    download_form = None

    if request.method == 'POST':
        if form.is_valid():
            starting_date = form.cleaned_data.get('starting_date')
            ending_date = form.cleaned_data.get('ending_date')
            contracts = Contract.objects.filter(person__is_doctor=False,
                                                type_contract=Contract.FC,
                                                starting_date__gte=starting_date,
                                                ending_date__lte=ending_date)
            # Create the DownloadForm instance here so you can pass it in the
            # context dict.
            download_form = DownloadForm(initial={
                'starting_date': starting_date,
                'ending_date': ending_date
            })

    return render(request, 'your_template.html',
                  {
                      'form': form,
                      'contracts': contracts,
                      'download_form': download_form
                  })

在实例化DownloadForm 时,视图将starting_dateending_date 设置为表单的初始参数,因此当模板呈现它时,它将在隐藏字段中包含查询参数。 (您可以使用浏览器进行确认。)

第 3 步

现在,修改您的模板以添加Download 按钮表单(这是您在上一步中添加到视图中的DownloadForm 实例):

{% extends "admin/base_site.html" %}
{% load i18n admin_urls admin_static admin_modify %}

{% block content %}

<form action="." enctype="db_personal/x-www-form-urlencoded" method="POST">
    <ul>
        {{ form.as_ul }}
    </ul>
    {% csrf_token %}
    <button type="submit">Search</button>
    <br> 
    <hr>
    {% if contracts %}
    <table border ="1" cellspacing="0">
        <th>Person</th>
        <th>Contract type</th>
        <th>Starting date</th>
        <th>Ending date</th>
        {% for contract in contracts %}
        <tr>
            <td>{{ contract.person }}</td>
            <td>{{ contract.type_contract }}</td>
            <td>{{ contract.starting_date }}</td>
            <td>{{ contract.ending_date }}</td>
        </tr>
        {% endfor %}
    </table>
    {% endif %}
</form>

{% if download_form %}
<form action="{% url 'download_data' %}"  method="POST">
    {% csrf_token %}
    {{ download_form.as_p }}
    <p>
        <input type="submit" class="btn" name="submit" value="Download" />
    </p>
</form>
{% endif %}

{% endblock %}

请注意,下载按钮的表单action 使用名为download_data 的命名网址。您必须向 urls.py 添加新的 url 规则以处理下载表单提交(请参阅下一步)。

第 4 步

向您的urls.py 添加新规则以处理下载表单提交。这将映射到我们将创建的新视图,以 CSV 格式返回请求的数据:

from django.conf.urls import patterns, url

from .views import filter_contracts, download_data

urls = patterns(
    # url prefix
    '',

    # view to render search form
    url(r'^contracts/$', filter_contracts, name='search_contracts'),

    # view to handle data download
    url(r'^contracts/download/$', download_data, name='download_data')
)

您必须根据已设置的内容调整 url 配置规则。以上只是一个指南和示例。

第 5 步

现在,在您的 views.py 中添加几个新视图来处理下载按钮提交和数据获取:

def get_csv_data(starting_date, ending_date):
    """
    Prepare data in csv format for download.
    * This is called by ``download_data`` to perform the query.
    * Do your query here and format the results as CSV using a csv
      writer or manually.
    * For this example, we're using some dummy data.
    """
    data = []
    num = 10
    for n in xrange(num):
        person = 'Person {}'.format(n + 1)
        type_contract = 'Some contract'
        start_date = starting_date
        end_date = ending_date
        data.append(', '.join([start_date, end_date, person, type_contract]))
    return '\n'.join(data)

def download_data(request):
    """
    Process a request to download data.
    * POST must contain 'starting_date' and 'ending_date'.
    """
    from django.http import HttpResponse

    try:
        assert request.method == 'POST'
        form = DownloadForm(request.POST)
        assert form.is_valid()
        starting_date = form.cleaned_data.get('starting_date')
        ending_date = form.cleaned_data.get('ending_date')
        assert starting_date and ending_date
        contracts = get_csv_data(starting_date, ending_date)
        assert contracts
    except AssertionError:
        error = 'Your request has some problems.'
        contracts = error

    attachment = 'contract_data.csv'
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment;filename="{}"'.format(attachment)
    response.write(contracts)
    return response

上面的get_csv_data 函数只是一个示例,用于准备一些虚拟数据进行测试。您应该将数据库查询代码放在那里以获取所需的查询集,然后将数据格式化为 CSV。 (示例函数手动格式化虚拟数据,但您应该使用 csv 模块来准备您的数据 - 请参阅此答案开头的 Django 示例以获取链接)。

总结

基本思路是:

  • 当您从查询中呈现合同搜索结果时,您只需向页面添加一个额外的DownloadForm 实例。这仅显示为Download 按钮,但它包含starting_dateending_date 的隐藏字段。
  • 当用户单击Download 按钮时,表单被提交到名为download_data 的新视图,该视图检查request.POST 字典并提取starting_dateending_date。然后,它准备查询集数据并以 CSV 格式呈现。
  • download_data 视图随后将响应作为内容类型为text/csv 的附件返回。用户的浏览器会自动将其作为下载文件处理。

代码中的错误和安全检查很少,但这应该可以帮助您入门。

【讨论】:

  • 但是如果我想要这两个功能,显示结果并导出到 csv。
  • 就我个人而言,我会将这些功能分为 2 个操作。这使得代码更易于阅读和维护。例如,您可以在前端有一个简单的按钮用于“下载结果”,并使用一个视图来查询结果并返回带有格式化数据的响应(例如在 csv 中)。即,让用户决定他/她是否只想查看 HTML 格式的数据或下载它。有些人可能不希望每次执行查询时都下载文件。换句话说,我会先选择简单,而不是让代码一次执行多个操作。
  • 据我所知,一个http响应对象只能有一种内容类型——你不能同时返回一个HTML页面和一个csv文件,让浏览器显示页面和下载文件。它们必须是 2 个单独的响应。
  • 是的,这就是我需要的。显示数据,然后使用另一个按钮导出到文件,但一旦数据已经显示。但是不知道怎么关联一个按钮和导出功能,导出之前过滤的数据。
  • 您可以做的是,当您显示查询结果时,还呈现一个“下载”表单——并将隐藏字段附加到表单,以便您可以嵌入原始查询参数。这样,当用户单击下载时,您将在表单中获得一个“查询”字段,您可以使用该字段重新查找查询,然后以 csv 格式返回结果。这可能是最简单的方法,它将作为一个开始。您最终将执行 2 个查询 - 一个用于原始查找,一个用于下载。但这没关系,因为它们是或可以被视为单独的操作。
猜你喜欢
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 2023-03-28
相关资源
最近更新 更多