You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django表单问题:需双击完成提交与状态切换,求单击实现方案

问题:问卷页面需双击提交按钮才能完成表单提交并显示结果

我开发了一个手机相关的问卷页面,需求是用户单击提交按钮时,完成表单提交并切换页面状态(显示结果区块)。但当前需双击才能完成操作,尝试添加模拟双击的脚本后问题仍未解决。相关代码如下:

models.py

class Items_buy(models.Model):

    class Meta:
        db_table = 'items_buy'
        verbose_name = 'Телефон который покупаем'
        verbose_name_plural = 'Телефоны которые покупаем'

    image_phone = ResizedImageField(size=[100,100], upload_to='for_sell/',verbose_name='Фотография модели телефона')
    model_produkt = models.TextField(max_length=80, verbose_name='Модель продукта ')
    text = models.TextField(max_length=500, verbose_name='Текст')
    max_prise = models.FloatField(verbose_name='Максимальная цена telefoha')
    image_phone_for_buy_bord = ResizedImageField(size=[100,100],upload_to='for_sell/',verbose_name='Фотография модели телефона ha prodazy')


    def __str__(self):
        return self.model_produkt

class Question(models.Model):

    class Meta:
        db_table = 'question'
        verbose_name = 'Вопрос к телефону'
        verbose_name_plural = 'Вопросы к телефону'

 
    items_buy = models.ForeignKey(Items_buy, on_delete=models.RESTRICT)
    titles= models.CharField(max_length=150,verbose_name='Заголовок вопросa')
    question_text =models.TextField(max_length=100, verbose_name='Заголовок вопросa text')
    #max_prise_qustion = models.FloatField(verbose_name='Максимальная цена')

   
    def __str__(self):
           return self.titles


class Choice(models.Model):

    class Meta:
        db_table = 'choice'
        verbose_name = 'Выбор ответа'
        verbose_name_plural = 'Выбор ответов'
    
    question = models.ForeignKey(Question, on_delete=models.RESTRICT,related_name="options")
    title = models.CharField(max_length=1000, verbose_name='Заголовок выбора')
    price_question = models.FloatField(verbose_name='Цена ответа')
    #lock_other = models.BooleanField(default=False, verbose_name='Смотреть другой вариант ответа')

    def __str__(self):
        return str(self.price_question)

class Answer(models.Model):
    class Meta:
        db_table = 'answer'
        verbose_name = 'Ответ на вопрос'
        verbose_name_plural = 'Ответы на вопросы'

    items_buy = models.ForeignKey(Items_buy, on_delete=models.RESTRICT)
    question = models.ForeignKey(Question, on_delete=models.RESTRICT)
    choice = models.ForeignKey(Choice, on_delete=models.RESTRICT)
    #created = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return str(self.items_buy)

forms.py

class AnswersForm(forms.Form):
    def __init__(self, *args, instance: Items_buy, **kwargs):
        self.instance = instance
        super().__init__(*args, **kwargs)
        questions = Question.objects.filter(items_buy_id=instance)
        existing_answers = {
            question_id: choice_id
            for question_id, choice_id in Answer.objects.filter(
                items_buy=self.instance
            ).values_list("question_id", "choice_id")
        }
        for question in questions:
            self.fields["question_%s" % question.id] = forms.ChoiceField(
                help_text=mark_safe(question.titles),
                label=mark_safe(question.question_text),
                choices=question.options.all().values_list("id", "title"),
                widget=forms.RadioSelect(attrs={"class": "form-check-input"}),
            )
            self.fields["question_%s" % question.id].initial = {} #existing_answers.get(
                #question.id, None
            #) 

    def save(self):
        answers_to_create = []
        for field, value in self.cleaned_data.items():
            if field.startswith("question_"):
                question_id = field.split("_")[-1]
                answers_to_create.append(
                    Answer(
                        items_buy=self.instance,
                        question_id=question_id,
                        choice_id=value,
                    )
                )
        Answer.objects.filter(items_buy=self.instance).delete()
        Answer.objects.bulk_create(answers_to_create)

views.py

def getqestionses(request, pk):
    iphone = get_object_or_404(Items_buy, pk = pk)
    total_score = iphone.answer_set.all().aggregate(total_score=Sum("choice__price_question"))["total_score"]
    form = AnswersForm(request.POST or None, instance=iphone)
    if form.is_valid():
        form.save() 
    return render(request, "getqestionses.html", {'form': form, 'total_score':total_score, 'iphone':iphone})

HTML

<!DOCTYPE html>
{% load static %}
{% load widget_tweaks %}
{% block content %}
<head>
  <link rel="stylesheet" href="{% static 'css/qestionses.css' %}" type="text/css">
</head>
<body>
  {% include 'navbar.html' %}
  <div class="div">
     <h1>{{ iphones.model_produkt }}</h1>  
    <form method="post">
        <div class="ded">
          {% csrf_token %}
          {% for field in form %}
          <div class="qestion">
            {{ field.label_tag}}
          </div>
          <div class="help_text">
          {{ field.help_text }}
          </div>
          <div class="form-check">
            {% for radio in field %}
            {{ radio.tag }}
            <div class="chack-button">
            {{ radio.choice_label }}
            </div>
            {% endfor %}
        </div>
      {% endfor %}
      <button type="submit" class="button">Submit</button>
    </form>
  </div>  
    <div class="next-block">
      <h1> {{ total_score }} </h1>
      <form action="{% url 'orderforsel' iphone.id %}"> 
        <button class="button-next-block">next page for order create</button>
      </form>
      </div>
  </div>  
  <script>
    const submitButton = document.querySelector('.button');
    const nextBlock = document.querySelector('.next-block');
    
    nextBlock.style.display = 'none'; // hide the next-block div initially
    
    submitButton.addEventListener('click', (event) => {
      event.preventDefault(); // prevent the form from submitting
      
      // Simulate a double click by waiting for a short delay before displaying the next-block div
      setTimeout(() => {
        nextBlock.style.display = 'block';
        submitButton.style.display = 'none';
      }, 200);
    });
  </script>
</body>
{% include 'info.html' %}
{% include 'end_navbar.html' %}
{% endblock %}

解决方案

问题根源

前端JS代码中使用event.preventDefault()阻止了表单的默认提交行为,导致第一次点击仅显示结果区块,但未实际提交表单保存答案,也无法获取后端计算的最新total_score。用户需要再次点击才能触发表单提交,因此出现双击才能完成操作的问题。

修复步骤

1. 修正后端视图逻辑

更新views.py,确保表单提交后重新计算最新的total_score,并处理total_score为None的情况:

def getqestionses(request, pk):
    iphone = get_object_or_404(Items_buy, pk=pk)
    # 初始化total_score,为空时设为0
    total_score = iphone.answer_set.all().aggregate(total_score=Sum("choice__price_question"))["total_score"] or 0
    form = AnswersForm(request.POST or None, instance=iphone)
    
    if request.method == 'POST' and form.is_valid():
        form.save()
        # 保存答案后重新计算最新的总分
        total_score = iphone.answer_set.all().aggregate(total_score=Sum("choice__price_question"))["total_score"] or 0
    
    return render(request, "getqestionses.html", {'form': form, 'total_score': total_score, 'iphone': iphone})

2. 调整前端模板,由后端控制显示状态

移除阻止表单提交的JS代码,改为通过后端变量控制提交按钮和结果区块的显示:

<!DOCTYPE html>
{% load static %}
{% load widget_tweaks %}
{% block content %}
<head>
  <link rel="stylesheet" href="{% static 'css/qestionses.css' %}" type="text/css">
</head>
<body>
  {% include 'navbar.html' %}
  <div class="div">
     <!-- 修正变量名:iphones → iphone -->
     <h1>{{ iphone.model_produkt }}</h1>  
    <form method="post">
        <div class="ded">
          {% csrf_token %}
          {% for field in form %}
          <div class="qestion">
            {{ field.label_tag}}
          </div>
          <div class="help_text">
          {{ field.help_text }}
          </div>
          <div class="form-check">
            {% for radio in field %}
            {{ radio.tag }}
            <div class="chack-button">
            {{ radio.choice_label }}
            </div>
            {% endfor %}
        </div>
      {% endfor %}
      <!-- 仅当未提交时显示提交按钮 -->
      {% if total_score == 0 %}
      <button type="submit" class="button">提交</button>
      {% endif %}
    </form>
  </div>  
    <!-- 提交后显示结果区块 -->
    {% if total_score > 0 %}
    <div class="next-block">
      <h1> {{ total_score }} </h1>
      <form action="{% url 'orderforsel' iphone.id %}"> 
        <button class="button-next-block">前往下单页面</button>
      </form>
      </div>
    {% endif %}
  </div>  
</body>
{% include 'info.html' %}
{% include 'end_navbar.html' %}
{% endblock %}

说明

修改后,用户单击提交按钮即可完成表单提交,后端保存答案并计算最新总分,页面刷新后自动显示结果区块并隐藏提交按钮,无需双击操作。同时修正了模板中变量名错误(iphones改为iphone),避免页面显示异常。

内容的提问来源于stack exchange,提问作者Богдан Савищев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 06:13:14