Django 表单字段动态显示
Posted
技术标签:
【中文标题】Django 表单字段动态显示【英文标题】:Django Form Fields Appear Dynamically 【发布时间】:2019-05-02 20:47:42 【问题描述】:我的 Django 应用程序中有一个包含超过 20 个字段的表单。有人要求我只显示前几个字段。填写完这些字段后,除了前面的字段外,还应显示接下来的几个字段。我怎样才能做到这一点?
以下是我的forms.py
class QuoteForm(forms.Form):
premium_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Premium Admin Stations Needed'))
standard_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Standard Admin Stations Needed'))
basic_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Basic Admin Stations Needed'))
messaging_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Messaging Stations Needed'))
auto_attendant = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Auto Attendants Needed'))
toll_service = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Toll-Free Services Needed'))
receptionist = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Receptionist Clients Needed'))
group_paging = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Group Paging Needed'))
FourG_backup = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# 4G Backups Needed'))
broadsoft_hub = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# BroadSoft Hubs Needed'))
polycom_410 = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Polycom VVX 410 Needed'))
spa_122 = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Linksys SPA122 Needed'))
yealink = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Yealink W52P POE Needed'))
我的观点.py:
def quote(request, phonenumber):
if request.method=='POST':
quote = PBXQuote.objects.filter(phone_number=phonenumber).order_by('id').last()
quote.premium_station = request.POST.get('premium_station')
quote.standard_station = request.POST.get('standard_station')
quote.basic_station = request.POST.get('basic_station')
quote.messaging_station = request.POST.get('messaging_station')
quote.auto_attendant = request.POST.get('auto_attendant')
quote.hunt_group = request.POST.get('hunt_group')
quote.toll_service = request.POST.get('toll_service')
quote.music_hold = request.POST.get('music_hold')
quote.call_recording = request.POST.get('call_recording')
quote.receptionist = request.POST.get('receptionist')
quote.group_paging = request.POST.get('group_paging')
quote.FourG_backup = request.POST.get('FourG_backup')
quote.broadsoft_hub = request.POST.get('broadsoft_hub')
quote.polycom_410 = request.POST.get('polycom_410')
quote.spa_122 = request.POST.get('spa_122')
quote.yealink = request.POST.get('yealink')
quote.ported_nums = request.POST.get('ported_nums')
quote.new_nums = request.POST.get('new_nums')
quote.directory_listing = request.POST.get('directory_listing')
quote.save()
return redirect('../../viewpbxquote//'.format(phonenumber))
else:
form = PBXQuoteForm()
context = 'form' : form
return render(request, 'Home/pbxquote.html', context)
我的 HTML 文件中的表单部分:
<section id="quote-section">
<div id="order-form-container">
<form class="login" method="post">
% csrf_token %
<h1>Quote</h1>
<h2>Hosted Stations</h2>
<div class="form-group">
<label for="premium_station" class="sr-only">Premium Stations</label>
form.premium_station Monthly: $32.00 | One-Time: $8.00 Each
</div>
<div class="form-group">
<label for="standard_station" class="sr-only">Standard Stations</label>
form.standard_station Monthly: $25.00 | One-Time: $8.00 Each
</div>
<div class="form-group">
<label for="basic_station" class="sr-only">Basic Stations</label>
form.basic_station Monthly: $14.00 | One-Time: $8.00 Each
</div>
<div class="form-group">
<label for="messaging_station" class="sr-only">Messaging Stations</label>
form.messaging_station Monthly: $4.95 | One-Time: N/A Each
</div><!--Ideally, this would be where the first displayed section would end. As long as at least one of these values changes, the next section would appear, as it shouldn't be necessary for every field unwanted to be set to '0'.-->
<h2>Services</h2>
<div class="form-group">
<label for="auto_attendant" class="sr-only">Auto Attendants</label>
<div class="form-group">
<label for="hunt_group" class="sr-only">Hunt Group Package</label>
<select class="form-control" name="hunt-group">
<option disabled selected>Hunt Group</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
<span>Monthly: N/A | One-Time: N/A</span>
</div>
<div class="form-group">
<label for="toll_service" class="sr-only">Toll-Free Services</label>
form.toll_service Monthly: $4.95 | One-Time: $14.95 Each
</div>
<div class="form-group">
<label for="music_hold" class="sr-only">Music On Hold</label>
<select class="form-control" name="music_hold">
<option disabled selected>Music On Hold</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
<span>Monthly: $9.95 | One-Time: N/A </span>
</div>
<div class="form-group">
<label for="call_recording" class="sr-only">
<select class="form-control" class="sr-only">
<option disabled selected>Call Recording</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
<span>Monthly: $9.95 | One-Time: N/A </span>
</div>
<div class="form-group">
<label for="receptionist" class="sr-only">Receptionist Clients</label>
form.receptionist Monthly: $9.95 | One-Time: $14.95 Each
</div>
<div class="form-group">
<label for="group_paging" class="sr-only">Group Paging</label>
form.group_paging Monthly: $9.95 | One-Time: $14.95 Each
</div>
<div class="form-group">
<label for="FourG_backup" class="sr-only">4G LTE Backup</label>
form.FourG_backup Monthly: $75.00 | One-Time: N/A Each
</div>
<div class="form-group">
<label for="broadsoft_hub" class="sr-only">BroadSoft Hub</label>
form.broadsoft_hub Monthly: $2.00 | One-Time: N/A Each
</div><!--The second section would end here. This time, every field that is a select would either be selected "Yes" or "No", and the next section would appear.-->
<h2>Equipment</h2>
<div class="form-group">
<div class="form-group">
<label for="polycom_410" class="sr-only">Polycom VVX 410</label>
form.polycom_410 One-Time: $144.00 Each
</div>
<div class="form-group">
<label for="spa_122" class="sr-only">Linksys SPA-122 ATA</label>
form.spa_122 One-Time: $34.90 Each
</div>
<div class="form-group">
<label for="yealink" class="sr-only">Yealink W52P</label>
form.yealink One-Time: $129.00 Each
</div>
<div class="form-group">
<label for="ported_nums" class="sr-only">Ported Numbers</label>
form.ported_nums Monthly: N/A | One-Time: $9.95 Each
</div>
<div class="form-group">
<label for="new_nums" class="sr-only">New Numbers</label>
form.new_nums Monthly: $1.00 | One-Time: $1.95 Each
</div>
<div class="form-group">
<label for="directory_listing" class="sr-only">Directory Listings</label>
form.directory_listing Monthly: $10.00 | One-Time: $20.00 Each
</div>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Submit</button>
</form>
</div>
</section>
我将非常感谢在此问题上提供的任何帮助,因为据我所知,我在网上没有找到任何可以完成我想做的事情的东西。
【问题讨论】:
【参考方案1】:您可以有两种形式,一种用于前半场,另一种用于其余字段。然后,您只需控制要传递给模板的表单。 没做过,不过好像不太难。 另一种选择是使用 javascript 隐藏字段,直到前半部分被填充,然后取消隐藏第二部分,并隐藏第一部分。
【讨论】:
嗯...我觉得这看起来不错。我想我可能会使用 JavaScript 选项,因为我需要用户提交另一个发布请求以将表单的上下文更新到模板。此外,这将涉及重写所有文件,而不仅仅是添加 JavaScript。谢谢! 回想起来,我不确定 JavaScript 选项是否会起作用。使用 引用除选择标记之外的任何字段(我忘记了语言的具体名称),我试图找到一个函数来检查该字段的值是否已更新。我发现的唯一事情是检查提交新 POST 请求时是否与初始值有差异,而我只想在更改某些答案时显示字段,而无需提交另一个 POST 请求。【参考方案2】:您可以使用表单向导来完成此操作。它创建了完全符合您需要的简洁表单,并且全部使用 Django 和 python,无需 javascript。
首先将 formtools 添加到已安装的应用中。
创建多个表单,而不仅仅是一个:
class QuoteForm1(forms.Form):
premium_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Premium Admin Stations Needed'))
standard_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Standard Admin Stations Needed'))
basic_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Basic Admin Stations Needed'))
class QuoteForm2(forms.Form):
messaging_station = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Messaging Stations Needed'))
auto_attendant = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Auto Attendants Needed'))
toll_service = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Toll-Free Services Needed'))
class QuoteForm3(forms.Form):
receptionist = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Receptionist Clients Needed'))
group_paging = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Group Paging Needed'))
FourG_backup = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# 4G Backups Needed'))
broadsoft_hub = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# BroadSoft Hubs Needed'))
class QuoteForm4(forms.Form):
polycom_410 = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Polycom VVX 410 Needed'))
spa_122 = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Linksys SPA122 Needed'))
yealink = forms.IntegerField(max_value=2000, min_value=0, required=False, widget = forms.NumberInput(attrs='class' : 'form-control', 'placeholder' : '# Yealink W52P POE Needed'))
然后在您的视图中从 SessionWizardView 导入,并指定表单:
from formtools.wizard.views import SessionWizardView
class QuoteFormView(SessionWizardView):
instance_dict = None
form_list = [QuoteForm1, QuoteForm2, QuoteForm3, QuoteForm4]
template_name = 'quote_form.html'
这样您可以为每个表单使用一个模板,但如果您需要为每个表单使用不同的模板:
TEMPLATES =
'0': 'quote_form1.html',
'1': 'quote_form2.html',
'2': 'quote_form3.html',
'3': 'quote_form4.html',
将 get_template_names 添加到您的视图中:
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
您使用 done 方法来保存表单,而不是通常的 form.is_valid:
def done(self, form_list, **kwargs):
data = k: v for form in form_list for k, v in form.cleaned_data.items()
# Reference your data
attribute = data['premium_station']
return HttpResponseRedirect('/redirect/')
并且在你的模板中你必须有 management_form 否则它将不起作用:
% extends "base.html" %
% load i18n %
% block head %
wizard.form.media
% endblock %
% block content %
<p>Step wizard.steps.step1 of wizard.steps.count </p>
<form action="" method="post">% csrf_token %
<table>
wizard.management_form
% if wizard.form.forms %
wizard.form.management_form
% for form in wizard.form.forms %
form
% endfor %
% else %
wizard.form
% endif %
</table>
% if wizard.steps.prev %
<button name="wizard_goto_step" type="submit" value=" wizard.steps.first ">% trans "first step" %</button>
<button name="wizard_goto_step" type="submit" value=" wizard.steps.prev ">% trans "prev step" %</button>
% endif %
<input type="submit" value="% trans "submit" %"/>
</form>
% endblock %
供参考
https://django-formtools.readthedocs.io/en/latest/wizard.html#
【讨论】:
哇,太不可思议了!我想我可能会使用类似的东西!非常感谢! :)以上是关于Django 表单字段动态显示的主要内容,如果未能解决你的问题,请参考以下文章
后台传回的Json数据怎么在HTML表单中显示并能动态编辑(添加、删除)
django - 动态添加 django 表单字段并保留用户输入