【问题标题】:Django Form Fields Appear DynamicallyDjango 表单字段动态显示
【发布时间】: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>

我将非常感谢在此问题上提供的任何帮助,因为据我所知,我在网上没有找到任何可以完成我想做的事情的东西。

【问题讨论】:

    标签: django python-3.x html django-forms django-templates


    【解决方案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#

    【讨论】:

    • 哇,太不可思议了!我想我可能会使用类似的东西!非常感谢! :)
    猜你喜欢
    • 2013-02-14
    • 1970-01-01
    • 2021-11-10
    • 2017-07-29
    • 2020-10-24
    • 1970-01-01
    • 2011-02-07
    • 2015-08-20
    相关资源
    最近更新 更多