Displaying jinja2 form fields based on attribute value

萝らか妹 提交于 2019-12-12 02:54:56

问题


I'm working on a flask app and using flask-wtf to help manage my forms.

There are 2 ways to register on my site - Either with or without an email token.

If the email has been confirmed the user gets an email containing:

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

Otherwise on the site itself the user could click on:

 http://127.0.0.1:5000/register

The following code can handle both cases:

@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)

My form class looks like:

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)])

I have a jinja2 form template that looks like:

{% 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 %}

and a jinja2 macro that looks like:

{% macro render_field(field)%}

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

{% endmacro %}

Right now this code works to display all the fields in the registerForm class. I'd like to modify/filter it so that if a token is used, I would like to display and validate only 2 form fields (username, password) . If no token - all 3 . How can this be done?

edit: switching

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

to

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

got it working


回答1:


One option would be to use inheritance, we'd define 2 form classes:

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)])

Then we'd modify the view to choose a form to use based on the existence of a token:

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)

Finally we'd modify the Jinja2 template removing the loop (as it's such a short form):

{% 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>


来源:https://stackoverflow.com/questions/35636678/displaying-jinja2-form-fields-based-on-attribute-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!