Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for WTForms range fields #194

Merged
merged 1 commit into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Release date: -
parameter for ``render_form``, ``render_field``, and ``render_form_row``.
- Add ``BOOTSTRAP_FORM_INLINE_CLASSES`` config for Bootstrap 5, defaults to ``row row-cols-lg-auto g-3 align-items-center``.
Also add a ``form_inline_classes`` parameter for ``render_form``.
- Add support for WTForms range fields (``DecimalRangeField`` and ``IntegerRangeField``).


1.8.0
Expand Down
8 changes: 4 additions & 4 deletions examples/bootstrap4/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ class ExampleForm(FlaskForm):
"""An example form that contains all the supported bootstrap style form fields."""
date = DateField(description="We'll never share your email with anyone else.") # add help text with `description`
datetime = DateTimeField(render_kw={'placeholder': 'this is a placeholder'}) # add HTML attribute with `render_kw`
datetimelocal = DateTimeLocalField()
datetime_local = DateTimeLocalField()
time = TimeField()
floating = FloatField()
integer = IntegerField()
decimalslider = DecimalRangeField()
integerslider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})
decimal_slider = DecimalRangeField()
integer_slider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})
email = EmailField()
url = URLField()
search = SearchField()
telephone = TelField()
image = FileField(render_kw={'class': 'my-class'}, validators=[Regexp('.+\.jpg$')]) # add your class
option = RadioField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
select = SelectField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
selectmulti = SelectMultipleField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
select_multiple = SelectMultipleField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
bio = TextAreaField()
title = StringField()
secret = PasswordField()
Expand Down
8 changes: 4 additions & 4 deletions examples/bootstrap5/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ class ExampleForm(FlaskForm):
"""An example form that contains all the supported bootstrap style form fields."""
date = DateField(description="We'll never share your email with anyone else.") # add help text with `description`
datetime = DateTimeField(render_kw={'placeholder': 'this is a placeholder'}) # add HTML attribute with `render_kw`
datetimelocal = DateTimeLocalField()
datetime_local = DateTimeLocalField()
time = TimeField()
floating = FloatField()
integer = IntegerField()
decimalslider = DecimalRangeField()
integerslider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})
decimal_slider = DecimalRangeField()
integer_slider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})
email = EmailField()
url = URLField()
search = SearchField()
telephone = TelField()
image = FileField(render_kw={'class': 'my-class'}, validators=[Regexp('.+\.jpg$')]) # add your class
option = RadioField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
select = SelectField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
selectmulti = SelectMultipleField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
select_multiple = SelectMultipleField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
bio = TextAreaField()
title = StringField()
secret = PasswordField()
Expand Down
18 changes: 18 additions & 0 deletions flask_bootstrap/templates/bootstrap4/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@
{% else %}
{{ field(class="form-control-file%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- elif field.type in ['DecimalRangeField', 'IntegerRangeField'] -%}
{% if field.errors %}
{{ field(class="form-control-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{% else %}
{% if field.errors %}
{{ field(class="form-control mb-2 mr-sm-2 mb-sm-0 is-invalid%s" % extra_classes, **kwargs)|safe }}
Expand All @@ -172,6 +178,12 @@
{% else %}
{{ field(class="form-control-file%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- elif field.type in ['DecimalRangeField', 'IntegerRangeField'] -%}
{% if field.errors %}
{{ field(class="form-control-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{% else %}
{% if field.errors %}
{{ field(class="form-control is-invalid%s" % extra_classes, **kwargs)|safe }}
Expand Down Expand Up @@ -199,6 +211,12 @@
{% else %}
{{ field(class="form-control-file%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- elif field.type in ['DecimalRangeField', 'IntegerRangeField'] -%}
{% if field.errors %}
{{ field(class="form-control-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{% else %}
{% if field.errors %}
{{ field(class="form-control is-invalid%s" % extra_classes, **kwargs)|safe }}
Expand Down
44 changes: 34 additions & 10 deletions flask_bootstrap/templates/bootstrap5/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,35 @@
{%- if field.flags.required %} required{% endif -%}">
{%- if form_type == "inline" %}
{{ field.label(class="visually-hidden")|safe }}
{% if field.errors %}
{{ field(class="form-control mb-2 mr-sm-2 mb-sm-0 is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control mb-2 mr-sm-2 mb-sm-0%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- if field.type in ['DecimalRangeField', 'IntegerRangeField'] %}
{% if field.errors %}
{{ field(class="form-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- else -%}
{% if field.errors %}
{{ field(class="form-control mb-2 mr-sm-2 mb-sm-0 is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control mb-2 mr-sm-2 mb-sm-0%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- endif %}
{% elif form_type == "horizontal" %}
{{ field.label(class="col-form-label" + (" col-%s-%s" % horizontal_columns[0:2]))|safe }}
<div class="col-{{ horizontal_columns[0] }}-{{ horizontal_columns[2] }}">
{%- if field.type in ['DecimalRangeField', 'IntegerRangeField'] %}
{% if field.errors %}
{{ field(class="form-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- else -%}
{% if field.errors %}
{{ field(class="form-control is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- endif %}
</div>
{%- if field.errors %}
{%- for error in field.errors %}
Expand All @@ -173,11 +189,19 @@
{%- endif %}
{%- else -%}
{{ field.label(class="form-label")|safe }}
{% if field.errors %}
{{ field(class="form-control is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- if field.type in ['DecimalRangeField', 'IntegerRangeField'] %}
{% if field.errors %}
{{ field(class="form-range is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-range%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- else -%}
{% if field.errors %}
{{ field(class="form-control is-invalid%s" % extra_classes, **kwargs)|safe }}
{% else %}
{{ field(class="form-control%s" % extra_classes, **kwargs)|safe }}
{% endif %}
{%- endif %}
{%- if field.errors %}
{%- for error in field.errors %}
<div class="invalid-feedback" style="display: block;">{{ error }}</div>
Expand Down
27 changes: 25 additions & 2 deletions tests/test_bootstrap4/test_render_form.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from flask import current_app, render_template_string
from flask_wtf import FlaskForm
from wtforms import BooleanField, FileField, MultipleFileField,\
PasswordField, RadioField, StringField, SubmitField
PasswordField, RadioField, StringField, SubmitField, IntegerRangeField,\
DecimalRangeField
from wtforms.validators import DataRequired
from flask_bootstrap import SwitchField

Expand Down Expand Up @@ -42,7 +43,7 @@ def description():


# test render SwitchField
def test_switchfield(app, client):
def test_switch_field(app, client):

class TestForm(FlaskForm):
remember = SwitchField('Remember me', description='Just check this')
Expand All @@ -62,6 +63,28 @@ def test_switch():
assert '<small class="form-text text-muted">Just check this</small>' in data


# test render IntegerRangeField and DecimalRangeField
def test_range_fields(app, client):

class TestForm(FlaskForm):
decimal_slider = DecimalRangeField()
integer_slider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})

@app.route('/range')
def test_range():
form = TestForm()
return render_template_string('''
{% from 'bootstrap4/form.html' import render_form %}
{{ render_form(form) }}
''', form=form)

response = client.get('/range')
data = response.get_data(as_text=True)
assert 'Decimal Slider' in data
assert 'Integer Slider' in data
assert 'form-control-range' in data


# test WTForm fields for render_form and render_field
def test_render_form_enctype(app, client):
class SingleUploadForm(FlaskForm):
Expand Down
25 changes: 24 additions & 1 deletion tests/test_bootstrap5/test_render_form.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from flask import render_template_string
from flask_wtf import FlaskForm
from flask_bootstrap import SwitchField
from wtforms import IntegerRangeField, DecimalRangeField


def test_switchfield(app, client):
def test_switch_field(app, client):

class TestForm(FlaskForm):
remember = SwitchField('Remember me', description='Just check this')
Expand All @@ -25,6 +26,28 @@ def test_switch():
assert '<small class="form-text text-muted">Just check this</small>' in data


# test render IntegerRangeField and DecimalRangeField
def test_range_fields(app, client):

class TestForm(FlaskForm):
decimal_slider = DecimalRangeField()
integer_slider = IntegerRangeField(render_kw={'min': '0', 'max': '4'})

@app.route('/range')
def test_range():
form = TestForm()
return render_template_string('''
{% from 'bootstrap5/form.html' import render_form %}
{{ render_form(form) }}
''', form=form)

response = client.get('/range')
data = response.get_data(as_text=True)
assert 'Decimal Slider' in data
assert 'Integer Slider' in data
assert 'form-range' in data


def test_form_group_class(app, client, hello_form):
@app.route('/default')
def test_default():
Expand Down