将 Javascript 计算传递给 Django 后端

Posted

技术标签:

【中文标题】将 Javascript 计算传递给 Django 后端【英文标题】:Pass Javascript Calculations to Django Backend 【发布时间】:2021-11-25 00:02:19 【问题描述】:

我有一个 html 表单,用户在输入表单中输入项目的名称和对应的值,这在表单提交到 Django 后端时会反映出来。

在我的 HTML 表单中,我包含了一些 javascript,因此这些值的总和会立即反映,而无需刷新,甚至在提交表单之前。

我的目标:

在idTotal下的HTML中发送Javascript计算的总量

                        <th scope="col">Total Equipment and Assets</th>
                        <th scope="col" id="Total"></th>

到类中

total_assets= models.IntegerField(null=True, blank=True, verbose_name='Total Assets')

提交后在Models.py中。

请注意,问题的原因是总值不是手动添加的,而是直接使用 Javascript 计算的。

这是一个让事情更清楚的示例。

这是 HTML 模板:

                    <tr>
                      <td>
                        <input
                          placeholder="Type in the Equipment and assets"
                          type="text"
                          class="form-control"
                          name="item_1"
                          id="item_1"
                          % if form.is_bound %value=" form.item_1.value "% endif %/>
                          % for err in form.item_1.errors %
                            <small class="text-danger mb-2 ml-2"> err </small>
                          % endfor %
                      </td>
                      <td>
                        <h6 style="float:left; margin-right:5px; margin-top:7px">$</h6>
                        <input
                          type="number"
                          class="form-control w-25 subtotal-group subtotal-group-1"
                          name="item_1_amount"
                          id="item_1_amount"
                          % if form.is_bound %value=" form.item_1_amount.value "% endif %/>
                          % for err in form.item_1_amount.errors %
                            <small class="text-danger mb-2 ml-2"> err </small>
                          % endfor %
                      </td>
                    </tr>
                    <tr>
                      <td>
                        <input
                          placeholder="Type in the Equipment and assets"
                          type="text"
                          class="form-control"
                          name="item_2"
                          id="item_2"
                          % if form.is_bound %value=" form.item_2.value "% endif %/>
                          % for err in form.item_2.errors %
                            <small class="text-danger mb-2 ml-2"> err </small>
                          % endfor %
                      </td>
                      <td>
                      <h6 style="float:left; margin-right:5px; margin-top:7px">$</h6>
                      <input
                        autocomplete="off"
                        type="number"
                        class="form-control w-25 subtotal-group subtotal-group-1"
                        name="item_2_amount"
                        id="item_2_amount"
                        % if form.is_bound %value=" form.item_2_amount.value "% endif %/>
                        % for err in form.item_2_amount.errors %
                          <small class="text-danger mb-2 ml-2"> err </small>
                        % endfor %
                    </td>
                    </tr>

这里是 Javacript

    <script>
    const q=(e,n=document)=>n.querySelector(e);
    const qa=(e,n=document)=>n.querySelectorAll(e);
    const results=;
    console. log(results)
    qa('[type="number"].form-control').forEach(input=>input.addEventListener('input',function(e)
      results[ this.name ]=Number( this.value );
      const resultGroupSet1 = [...qa('.subtotal-group-1')]
                              .map(s => Number(s.value))
                              .reduce((a,v) => a+v);
      q('th#Total').textContent = resultGroupSet1;

    ));
    </script>

这是在 HTML 模板中反映总数的地方

                  <thead class="table-light">
                      <tr>
                        <th scope="col">Total Equipment and Assets</th>
                        <th scope="col" id="Total"></th>
                      </tr>
                    </thead>

这是models.py

    item_1                      = models.CharField(max_length=100,null=True, blank=True, verbose_name='Item 1')
    item_1_amount               = models.IntegerField(null=True, blank=True, verbose_name='Item 1 Amount')
    item_2                      = models.CharField(max_length=100,null=True, blank=True, verbose_name='Item 2')
    item_2_amount               = models.IntegerField(null=True, blank=True, verbose_name='Item 2 Amount')
    total_assets                = models.IntegerField(null=True, blank=True, verbose_name='Total Assets')

以下是观点:

def add_bp(request):
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = infoForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            form.save()
            b_name = form.cleaned_data.get('bName')
            messages.success(request, f'PDF created for b_name!')
            return redirect('application:core')
    # if a GET (or any other method) we'll create a blank form
    else:
        form = infoForm()
    return render(request, 'application/template.html', 'form': form, )

【问题讨论】:

【参考方案1】:

为什么不在 Django Backend 中做这个计算?

我的建议是正常传递所有参数,然后在模型保存中添加一个侦听器(每次将元素保存到表中时,这段代码都会在保存之前运行):

from django.db.models.signals import pre_save
from django.dispatch import receiver

@receiver(pre_save, model_class)
def form_pre_save(instance, *args, **kwargs):
    instance.total_assets = instance.item_1_amount + instance.item_2_amount

这样,当您想将此类元素保存在不同的位置(例如在后端)时,您不必重新编写执行此操作的代码,而只需保存实例即可。

你可以阅读更多关于信号pre_save函数here

【讨论】:

【参考方案2】:

将 html 更新为:

<thead class="table-light">
    <tr>
        <th scope="col">Total Equipment and Assets</th>
        <th scope="col">
            <!-- Value which is visible (calculated using JS) -->
            <span id="Total"></span>

            <!-- Add a hidden input to store value (value calculated and assigned using JS) -->
            <input type="hidden" name="total_assets" value="0" id="total_assets">
        </th>
    </tr>
</thead>

更新脚本以将resultGroupSet1 分配为:

文本内容到带有id=Total的span标签 隐藏输入的值name=total_assets
// Assign result to span tag which is visible
q('span#Total').textContent = resultGroupSet1;

// Assign result as value to hidden input field with name total_assets
q('input#total_assets').value = resultGroupSet1;

视图没有其他变化。

当使用带有name="total_assets" 的输入字段时,该值将被传递到请求正文,并可通过request.POST 访问。在这里,由于total_assets 字段是隐藏的,因此用户看不到它,并且在提交表单时该值在 POST 数据中仍然可用。因此,当调用form.save() 时,计算值(使用JS)将被保存。

【讨论】:

【参考方案3】:

您正在寻找的可能是 &lt;input type="hidden" ...&gt;,最终用户看不到它,它包含在表单提交中

【讨论】:

【参考方案4】:

我假设您的问题是如何获取此元素中的值:

<th scope="col" id="Total"></th>

您只需在 html 代码中添加 input 元素并将名称添加到其中:

<th scope="col"><input id="Total" name="total_assets" value=""></th>

然后在你的views.py中:

def add_bp(request):
if request.method == 'POST':
    form = infoForm(request.POST)
    if form.is_valid():
        form.save()
        

您也可以手动获取总计:

def add_bp(request):
if request.method == 'POST':
    total_assets = request.POST.get("total_assets")

【讨论】:

我不希望它被用户添加。我已经使用 javascript 来自动计算总金额。我可以添加与其他输入相同的输入,但它已经在计算 首先,th 中的输入有助于存储值并在用户发布表单时获取值。其次,您的 javascript 代码对用户是可见的,他们可以更改代码并放置他们想要的任何内容。

以上是关于将 Javascript 计算传递给 Django 后端的主要内容,如果未能解决你的问题,请参考以下文章

如何将javascript变量传递给django模板标签

将 django 变量传递给 javascript

Django - 将变量传递给同一脚本标签内的 javascript 文件

将 Javascript 变量传递给 Django 标签

使用 django 将 STATIC_URL 传递给文件 javascript

Django模板Javascript将python变量传递给javascript