【问题标题】:Django: Pass arguments from other form to submit buttonDjango:从其他表单传递参数以提交按钮
【发布时间】:2021-02-01 14:04:53
【问题描述】:

我正在构建一个简单的 Django 应用程序,让用户可以跟踪特定日期的内容:

它使用大写形式记录带有名称和日期的条目。

<form action="" method="post" style="margin-bottom: 1cm;">
        {% csrf_token %}

        <div class="form-group">
            {{ form.entry_name.label_tag }}
            <div class="input-group">
                <input type="text" class="form-control" id="{{ form.entry_name.id_for_label }}" name="{{ form.entry_name.html_name }}" aria-label="new entry field">
                {{ form.entry_date }}

                <div class="input-group-append">
                    <button type="submit" class="btn btn-primary">Add</button>
                </div>
            </div>

            <small id="{{ form.entry_name.id_for_label }}Help" class="form-text text-muted">This can be anything you want to track: An activity, food, how you slept, stress level, etc.</small>
        </div>
    </form>

表单下方有快速添加按钮,可让用户快速添加具有特定名称的新条目。另外,我想使用上面表格中选择的日期。即,如果用户在上方表单中设置了日期,但随后单击了建议的按钮之一,它仍应使用选定的日期来添加新条目。

这是建议按钮的代码当前的样子:

{% if entry_counts and entry_dict|length > 0 %}
    <div class="card" style="margin-bottom: 1cm;">
        <div class="card-body">
            <div class="card-title">Suggested entries</div>
            {% for name, count in entry_counts.items %}
                <form method="post" action="{% url 'app:add_entry_with_date' name form.entry_date.value %}" style="display: inline-block;">
                    {% csrf_token %}
                    <button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;">{{ name }}</button>
                </form>
            {% endfor %}
        </div>
    </div>
    {% endif %}

我正在尝试访问所选日期并将其传递给相应的视图:action="{% url 'app:add_entry_with_date' name form.entry_date.value %}",但它仍然在默认日期(今天)而不是在所选日期添加条目。 我的猜测是,问题出在&lt;button type="submit" class="btn btn-secondary" name="{{ name }}" style="margin-bottom: 5px;"&gt;{{ name }}&lt;/button&gt; 上。这只是通过name而不是提交时的日期吗?

以下是相关的 URL 模式:

class DateConverter:
    regex = '\d{4}-\d{2}-\d{2}'

    def to_python(self, value):
        return datetime.datetime.strptime(value, '%Y-%m-%d')

    def to_url(self, value):
        return value


register_converter(DateConverter, 'yyyymmdd')


urlpatterns = [
    path('', views.index, name='index'),
    path('add/<entry_name>/', views.add_entry, name='add'),
    path('add/<entry_name>/<yyyymmdd:entry_date>/', views.add_entry, name='add_entry_with_date'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

因此,无论何时添加新条目(有或没有特定日期),都会调用我的 add_entry 视图:

@login_required
def add_entry(request, entry_name, entry_date=datetime.date.today()):
    # only works for post
    # if request.method == 'POST':
    entry_name = entry_name.strip().lower()
    entry = Entry.objects.create(name=entry_name, date=entry_date, owner=request.user)
    return HttpResponseRedirect(reverse('app:index'))

【问题讨论】:

  • 您正试图通过 URL 传递日期值,对吗? “这只是传递名称而不是提交时的日期吗?”似乎与问题无关。据我所知,提交按钮不应该用于传递数据,并且您在该表单中没有任何 input 元素。无论如何,我有一种预感,问题出在您的视图中,而不是您的 HTML 中,因此如果您分享 add_entry_with_date 的详细信息可能会有所帮助。
  • 我没有输入元素,因为我希望用户能够只单击一个按钮而无需填写文本字段和日期字段。或者我可以在设置值的地方做一些不可见的输入吗?此外,通过按钮传递条目名称是可行的。我刚刚更新了描述以添加我的 URL 并按照您的建议进行查看。是的,我正在尝试通过快速添加按钮的 URL 传递日期。我用邮递员测试了 URL,它应该可以工作。
  • 您绝对可以进行隐形输入:只需使用type="hidden"。事实上,Django 是这样渲染csrf_token 的。无论如何,我发布了一个答案,如果有帮助,请告诉我。

标签: python html django forms django-templates


【解决方案1】:

您正在尝试将日期值作为 URL 的一部分传递,

{% url 'app:add_entry_with_date' name form.entry_date.value %}

但是,form.entry_date.value 不会有定义的值,除非您的表单在传递给模板进行渲染之前被绑定。因此,您的 add_entry 视图可能是通过 URL 模式 add 而不是 add_entry_with_date 调用的。

您当前代码的另一个挑战是您希望使用相同的日期类型 input 元素 ({{ form.entry_date }}) 作为不同的单独 HTML 表单的源(您有第一个表单用于添加条目,并且然后您为每个建议的条目提供一个表格)。当页面已在浏览器中呈现时更改该输入的值不会更新建议条目 forms 的 action URL — 除非您使用 JavaScript。

我认为使现有代码工作的最快方法是编写一些 JavaScript 来在日期输入值更改时为建议条目 forms 操作 action 属性。

虽然操作action 属性看起来很奇怪,而且我相信您的视图应该只适用于 POST 请求,应该只使用 POST 数据而不依赖于 URL 参数。因此我建议你使用隐藏的inputs,例如

<input type="hidden" name="variable-name" value="temporary-date-value-here">

然后让 JavaScript 操作这些 input 元素的值而不是表单 action 属性。当然你也必须更新视图。

更新:用于跨表单同步输入的示例 JS

HTML:

<html>

    <head>
        <title>Sample synchronization of inputs across forms</title>
    </head>

    <body>
        <h1>Sample synchronization of inputs across forms</h1>

        <h2>Form 1</h2>
        <form>
            <input class="synchronized-inputs" type="date" name="input_date">
        </form>

        <h2>Form 2</h2>
        <form>
            <input class="synchronized-inputs" type="date" name="input_date">
        </form>

        <script src="sync-inputs-across-forms.js" type="text/javascript"></script>

    </body>
    
</html>

JavaScript (sync-inputs-across-forms.js):

var syncedInputs = document.getElementsByClassName('synchronized-inputs');

Array.from(syncedInputs).forEach((source) => {
    source.addEventListener('change', () => {
        Array.from(syncedInputs).forEach((target) => {
            target.value = source.value;
        });
    });
});

注意:

  • 没有 JS,在一个表单中选择日期不会更新另一个表单的值
  • 如原始答案所示,您希望对建议的输入表单使用隐藏输入。为此,只需将另一种形式的type="date" 更改为type="hidden"。当值在 DOM(不可见部分)中被跟踪时,同步仍然有效。

【讨论】:

  • 你有一个例子来说明必要的 JavaScript 可能是什么样的吗?我应该何时/如何称呼它?基本上,每当用户在主/上部表单中选择日期时,对吗?然后它应该将该值复制到建议条目的不可见输入中。不知道如何用 JS 做到最好。
  • @CGFoX 我用示例 JS 更新了答案。您只需声明事件侦听器即可“调用”它——这是 JavaScript 方式,您对浏览器事件(例如用户点击)做出反应。是的,当用户操作主窗体的小部件时,脚本会将主/上窗体的日期小部件的值复制到不可见的输入中。
  • 如何获取隐藏日期的初始值?我只是注意到在我主动选择日期选择器中的日期之前它不起作用。我想出了如何使用 JS 在窗口加载时从日期选择器中复制默认值,但这在 Django 中是否也可以实现?
  • @CGFoX 在input 标签内设置value 属性来初始化它们的值。如果您想在服务器端执行此操作,是的,使用 Django 您可以添加 value="{% now "Y-m-d" %}" 以使用当前日期进行初始化。当然,您也可以使用 JS 在客户端执行此操作。
猜你喜欢
  • 1970-01-01
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 2012-09-11
相关资源
最近更新 更多