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,提问作者Богдан Савищев
相关产品推荐
相关产品推荐

