首页 > 解决方案 > 两个 POST 请求之间的通信

问题描述

问题

我有一个 Django 表单,用户在其中提交文本搜索字符串(下面的完整示例设置)。

问题:如何(并且应该)两个 POST 请求,当前由绑定到相同 URL 模式的相同视图处理,通过第一个 POST 请求将数据传递给第二个请求相互“交谈”?

问题的症结在下面的块elif request.POST["router"] == "csv"中:我需要results从第一个 POST 请求中访问对象,但是基本的 Python 范围/控制流阻止了我这样做。

目前,所有内容都位于同一个 URLconf 中path,并且基于 (1) 请求是否为 GET/POST,(2) POST 请求name/value属性来自其<input>标签的内容而不同地处理。

设置

进口:

import csv
from time import time_ns

from django import forms
from django import models
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.urls import path

my_app/urls.py

urlpatterns = [
    path("run/<uuid:pk>", views.run),
]

my_app/forms.py

class RunForm(forms.Form):
    start = forms.DateTimeField()
    query = forms.CharField()

my_app/templates/my_app/run.html

<form method="post">
    {% csrf_token %}
    <h1>Launch a search</h1>
    <table>
    {{ form.as_table }}
    </table>
    <input type="hidden" name="router" value="run">
    <input type="submit" value="Submit">
</form>

my_app/templates/my_app/results.html

<table>
{% for row in results %}
<tr>
{% for val in row %}
<td>{{ val }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>

<form method="post">
  {% csrf_token %}
  <input type="hidden" name="router" value="csv">
  <input type="submit" value="Download to CSV">
</form>

my_app/views.py

def run(request, pk):
    if request.method == "POST":
        if request.POST["router"] == "run":
            form = RunForm(request.POST)
            if form.is_valid():
                obj = get_object_or_404(MyModel, pk=pk)
                # Get some dynamic results from database based
                # on `obj` and the form fields.
                # The Python output is a lists of lists
                # that should be rendered to a downloadable HTML <table>
                results = [
                    [1, 2, 3],
                    [4, 5, 6],
                ]
                return render(request, "my_app/results.html", {"results": results})
        elif request.POST["router"] == "csv":
            response = HttpResponse(content_type="text/csv")
            response["Content-Disposition"] = f"attachment; filename=results-{time_ns():d}.csv"
            writer = csv.writer(response)
            # Ah!  Now I need to access `results` from above.  Do I inject
            # `results` into another <form> on my_app/results.html?
            # i.e.:
            # for row in results:
            #     writer.writerow(row)
            return response
    else:
        form = RunForm()
    return render(request, "my_app/run.html", {"form": form})

my_app/models.py

class MyModel(models.Model):
    # Not important what this does for this example,
    # just a placeholder.

标签: pythondjangodjango-forms

解决方案


你有几个我能想到的选择:

返回结果并与第二个请求一起发回

您可以让视图中的第一个路径(处理router="run"分支的路径)返回 JSONResponse 而不是HTTPResponse生成或呈现表单的对象,结果已经插入到<form>元素中。无论哪种方式,想法是将结果存储在前端,并将它们作为参数返回到另一个router="csv"分支

存储到 Django 会话

您还可以利用 Django 会话,将字符串化结果列表存储到分支中request.session['results'],然后request.session['results']router="csv"分支中进行检查。然后只需检查request.session['results']CSV 分支。


推荐阅读