在 SelectField 和 HiddenField 之间动态更改 WTForms 字段类型

Kel*_*ila 5 python flask flask-wtforms

我有一个 WTForms 字段(value_currency),我希望有时是 SelectField,有时是 HiddenField。我对创建新项目和编辑现有项目的页面使用相同的视图和模板。如果我加载页面来创建一个新项目,我希望这个字段是一个 SelectField,如果我加载页面来编辑一个现有项目,我希望这个字段是一个 HiddenField,因为它是一个不可编辑的字段。

这是我到目前为止所拥有的:

形式

class PromoForm(Form):
    value = StringField('value')
    currencies = Currency.query.order_by(Currency.id).all()
    currency_choices = []
    for currency in currencies:
        currency_choice = (currency.id, currency.name)
        currency_choices.append(currency_choice)
    value_currency = SelectField('value_currency', choices=currency_choices)
Run Code Online (Sandbox Code Playgroud)

看法

@app.route('/promo/<id>', methods=['GET', 'POST'])
@login_required
def promo(id):
    form = PromoForm()
    # Existing promo will pass in its id
    # id = 0 if a new promo is to be created
    if id != str(0):
        # Load existing promo
        promo = Promo.query.get(id)
        # display value in decimal format
        form.value.default = "{0}.{1:0>2}".format(
            promo.value_cents//100, promo.value_cents%100)
        form.process()
        return render_template('promo.html', promo=promo, form=form)
    else:
        # New promo
        audit_log('GET', client, session=session)
        return render_template('promo.html', form=form)
Run Code Online (Sandbox Code Playgroud)

模板

{% extends "base.html" %}
{% block content %}
    {% if promo is defined %}
        <form action="{{ url_for('.promo', id=promo.id) }}" method="post">
    {% else %}
        <form action="{{ url_for('.promo', id=0) }}" method="post">
    {% endif %}
    {{ form.hidden_tag() }}
    <div>
        <label for="value">Promo Value</label>
        {% if promo is defined %}
            {{ form.value() }}
        {% else %}
            {{ form.value() }}
        {% endif %}
        {% for error in form.value.errors %}
            <span class="error">[{{ error }}]</span>
        {% endfor %}
        {% if promo is defined %}
            # ----> Promo.value_currency should be a hidden field here (Doesn't work)
            {{ promo.value_currency }}
        {% else %}
            # ----> Promo.value_currency is a select field here (Currently works)
            {{ form.value_currency() }}
        {% endif %}
    </div>
    <div class="submit_btn">
        {% if promo is defined %}
            <input type="submit" value="Update Promo">
        {% else %}
            <input type="submit" value="Create Promo">
        {% endif %}
    </div>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

我知道我可以简单地对隐藏的输入元素进行硬编码并使用 Jinja 放入值,但我更喜欢使用 WTForms 来完成,而不是对任何表单元素进行硬编码。那可能吗?

flo*_*sla 5

请参阅(重复)问题:Flask,WTForms:有没有办法使表单中的 StringField 暂时隐藏?

您不能只省略该字段,也不能更改其对象类型(从 SelectField 到 HiddenField)。

但是,您可以更改其小部件对象。将其替换为HiddenInput.

from wtforms.widgets import HiddenInput

class PromoForm(Form):
    value = StringField('value')
    currencies = Currency.query.order_by(Currency.id).all()
    currency_choices = []
    for currency in currencies:
        currency_choice = (currency.id, currency.name)
        currency_choices.append(currency_choice)
    value_currency = SelectField('value_currency', choices=currency_choices)
    
    def hide_value_currency(self, value):
        """
        Hide the value_currency field by morping it into a 
        HiddenInput.    
        """ 
        self.value_currency.widget = HiddenInput()
        # wtforms chokes if the data attribute is not present
        self.value_currency.data = value
        # wtforms chokes on SelectField with HiddenInput widget
        # if there is no _data() callable
        self.value_currency._value = lambda: value
        
Run Code Online (Sandbox Code Playgroud)

form.hide_value_currency(pre_set_value)需要时在您的视图中调用。

模板中不需要任何逻辑。