根据属性值显示 jinja2 表单字段

Displaying jinja2 form fields based on attribute value

我正在开发一个 flask 应用程序并使用 flask-wtf 来帮助管理我的表单。

有两种方法可以在我的网站上注册 - 使用或不使用电子邮件令牌。

如果电子邮件已被确认,用户将收到一封包含以下内容的电子邮件:

http://127.0.0.1:5000/register/ImNsdWVtYXJpbmUzQG1haWxpbmF0b3IuY29tIg.Ca9oUQ.bRJmGYQ1wNqfcQFx1pYyoCEy2oM

否则,用户可以在网站本身上点击:

 http://127.0.0.1:5000/register

以下代码可以处理这两种情况:

@blueprint.route("/register/", defaults={'token': ''}, methods=['GET', 'POST'])
@blueprint.route("/register/<token>", methods=['GET', 'POST'])
def register(token):
    form = RegisterForm(request.form, csrf_enabled=False)
    email = confirm_token(token)
    if form.validate_on_submit():
        new_user = User.create(username=form.username.data,
                              email=form.email.data,
                               password=form.password.data,
                               active=True)
return render_extensions('public/register.html', form=form , email=email)

我的表单 class 看起来像:

class RegisterForm(Form):
    username = StringField('Username', validators=[DataRequired(), Length(min=3, max=25)])
    email = StringField('Email', validators=[DataRequired(), Email(), Length(min=6, max=40)])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=40)])

我有一个 jinja2 表单模板,如下所示:

{% from "macros.html" import render_field  %}
<div class="container-narrow">
  <h1>Register</h1>
    <br/>
       <form id="registerForm" class="form form-register" method="POST" action="" role="form">
        {{ form.hidden_tag() }}
        {% for field in form %}
            {% if field.label!='Email' or email=='False' %}
                {{ render_field(field) }}
            {% endif %}
        {% endfor %}
        <p><input class="btn btn-default btn-submit" type="submit" value="Register"></p>
</div>
{% endblock %}

和一个看起来像这样的 jinja2 宏:

{% macro render_field(field)%}

<div class="form-group">
{#                {{field.label}}#}
                {{field(placeholder=field.label.text, class_="form-control")}}
</div>

{% endmacro %}

现在这段代码可以显示 registerForm 中的所有字段 class。我想 modify/filter 它以便如果使用令牌,我只想显示和验证 2 个表单字段 (username, password) 。如果没有令牌 - 所有 3。这怎么能做到?

编辑:切换

{% if field.label!='Email' or email=='False' %}

{% if field.label.text!='Email' or email=='False' %}

成功了

一个选择是使用继承,我们定义 2 种形式 类:

class TokenRegisterForm(Form):

    username = StringField('Username', 
        validators=[DataRequired(), Length(min=3, max=25)])

    password = PasswordField('Password', 
        validators=[DataRequired(), Length(min=6, max=40)])


class RegisterForm(TokenRegister):

    email = StringField('Email',
        validators=[DataRequired(), Email(), Length(min=6, max=40)])

然后我们将修改视图以根据令牌的存在选择要使用的表单:

def register(token):
    """Register a user"""

    # Create the registration form based on the presence of a token. If the user 
    # has specified a valid token then we can use that to get retrieve their 
    # email address, if not we need to the registration form to ask it.
    email = confirm_token(token)
    if email:
        form = TokenRegisterForm(request.form, csrf_enabled=False)
    else
        form = RegisterForm(request.form, csrf_enabled=False)

    # Validate the user's submission
    if form.validate_on_submit():

        # Collate the details for the new user
        user_details = form.data
        user_details['active'] = True
        if email:
            user_details['email'] = email

        # Create the new user
        new_user = User.create(**user_details)

    return render_extensions('public/register.html', form=form, email=email)

最后,我们将修改 Jinja2 模板以删除循环(因为它是如此简短的形式):

{% from "macros.html" import render_field  %}

<div class="container-narrow">
    <h1>Register</h1>
    <br/>
    <form 
        class="form form-register" 
        id="registerForm" 
        method="POST"
        role="form"
        >
        {{ form.hidden_tag() }}
        {{ render_field(field.username) }}
        {% if form.email %}
            {{ render_field(field.email) }}
        {% endif %}
        {{ render_field(field.password) }}
        <p>
            <input 
                class="btn btn-default btn-submit" 
                type="submit" 
                value="Register">
        </p>
</div>