Bootstrap 4 & 5 helper for Flask projects providing Jinja macros for forms, tables, navigation, and utilities.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Helper functions for form field detection, table title generation, template error handling, and custom field components that extend Bootstrap-Flask functionality.
Utility function for identifying hidden form fields in templates.
def is_hidden_field_filter(field) -> bool:
"""
Check if a WTForms field is a hidden field.
Args:
field: WTForms field object
Returns:
bool: True if field is an instance of HiddenField, False otherwise
Usage:
- Used as Jinja filter: bootstrap_is_hidden_field
- Registered globally in Jinja environment
- Helps templates conditionally render hidden fields
Example:
{% for field in form %}
{% if not bootstrap_is_hidden_field(field) %}
{{ render_field(field) }}
{% endif %}
{% endfor %}
"""Automatically generate human-readable table column titles from SQLAlchemy model metadata.
def get_table_titles(data, primary_key, primary_key_title) -> list:
"""
Detect and build table titles from SQLAlchemy ORM objects.
Args:
data (list): List of SQLAlchemy model instances
primary_key (str): Primary key field name
primary_key_title (str): Display title for primary key column
Returns:
list: List of (field_name, display_title) tuples
Behavior:
- Extracts column names from first object's __table__.columns
- Converts snake_case to Title Case (user_name → User Name)
- Excludes fields starting with underscore (private fields)
- Sets primary key column to specified title
- Returns empty list if data is empty
Requirements:
- Only works with SQLAlchemy ORM objects
- Objects must have __table__ attribute with columns
Example:
User model columns: id, first_name, last_name, email, _password_hash
Returns: [('id', 'User ID'), ('first_name', 'First Name'),
('last_name', 'Last Name'), ('email', 'Email')]
"""Helper function for raising runtime errors from within Jinja templates.
def raise_helper(message) -> None:
"""
Raise a RuntimeError from within templates.
Args:
message (str): Error message to display
Raises:
RuntimeError: Always raises with provided message
Usage:
- Registered as 'raise' in Jinja globals
- Allows templates to throw errors for debugging
- Useful for template development and error handling
Template Usage:
{% if not required_variable %}
{{ raise('Required variable is missing') }}
{% endif %}
"""Custom WTForms field that renders as a Bootstrap switch instead of a checkbox.
class SwitchField(BooleanField):
"""
A wrapper field for BooleanField that renders as a Bootstrap switch.
Inherits from WTForms BooleanField with identical functionality
but renders with Bootstrap switch styling instead of checkbox.
Attributes:
All BooleanField attributes and methods available
Bootstrap Versions:
- Bootstrap 4: Uses custom-switch classes
- Bootstrap 5: Uses form-switch classes
"""
def __init__(self, label=None, **kwargs):
"""
Initialize switch field.
Args:
label (str, optional): Field label text
**kwargs: Additional arguments passed to BooleanField
Supported kwargs:
- validators: List of validation functions
- default: Default value (True/False)
- description: Help text for field
- render_kw: Additional HTML attributes
"""Bootstrap-Flask registers several Python utilities as Jinja global variables during extension initialization.
# Available in all templates after Bootstrap extension initialization
bootstrap_is_hidden_field # is_hidden_field_filter function
get_table_titles # Table title generation function
warn # warnings.warn function for deprecation notices
raise # raise_helper function for template errors
bootstrap # Extension instance with load_css(), load_js(), etc.# Form definition
class ContactForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
csrf_token = HiddenField() # CSRF protection
honeypot = HiddenField() # Bot detection
message = TextAreaField('Message', validators=[DataRequired()])
submit = SubmitField('Send Message')<!-- Template - render only visible fields -->
<form method="post">
{% for field in form %}
{% if not bootstrap_is_hidden_field(field) and field.type != 'SubmitField' %}
<div class="mb-3">
{{ field.label(class="form-label") }}
{{ field(class="form-control") }}
{% if field.errors %}
{% for error in field.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
{% endif %}
{% endfor %}
<!-- Render hidden fields separately -->
{% for field in form %}
{% if bootstrap_is_hidden_field(field) %}
{{ field() }}
{% endif %}
{% endfor %}
{{ form.submit(class="btn btn-primary") }}
</form># SQLAlchemy model
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
product_name = db.Column(db.String(100), nullable=False)
unit_price = db.Column(db.Numeric(10, 2))
in_stock = db.Column(db.Boolean, default=True)
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
_internal_code = db.Column(db.String(50)) # Excluded (starts with _)
# View function
@app.route('/products')
def products():
products = Product.query.all()
# Automatically generate titles
titles = get_table_titles(products, 'id', 'Product ID')
# Returns: [('id', 'Product ID'), ('product_name', 'Product Name'),
# ('unit_price', 'Unit Price'), ('in_stock', 'In Stock'),
# ('category_id', 'Category Id'), ('created_at', 'Created At')]
return render_template('products.html', products=products, titles=titles)<!-- Template with auto-generated titles -->
{% from 'base/table.html' import render_table %}
{{ render_table(products, titles=titles) }}# Override auto-generated titles with custom ones
@app.route('/products')
def products():
products = Product.query.all()
# Custom titles for better display
titles = [
('id', '#'),
('product_name', 'Product'),
('unit_price', 'Price ($)'),
('in_stock', 'Available'),
('created_at', 'Date Added')
]
return render_template('products.html', products=products, titles=titles)# Form with switch fields
class UserPreferencesForm(FlaskForm):
email_notifications = SwitchField('Email Notifications')
sms_notifications = SwitchField('SMS Notifications')
dark_mode = SwitchField('Dark Mode')
auto_save = SwitchField('Auto-save Documents')
public_profile = SwitchField('Public Profile')
submit = SubmitField('Save Preferences')<!-- Template rendering switches -->
{% from 'bootstrap5/form.html' import render_field %}
<form method="post">
{{ form.hidden_tag() }}
<div class="mb-4">
<h5>Notification Settings</h5>
{{ render_field(form.email_notifications) }}
{{ render_field(form.sms_notifications) }}
</div>
<div class="mb-4">
<h5>Interface Settings</h5>
{{ render_field(form.dark_mode) }}
{{ render_field(form.auto_save) }}
</div>
<div class="mb-4">
<h5>Privacy Settings</h5>
{{ render_field(form.public_profile) }}
</div>
{{ render_field(form.submit) }}
</form><!-- Debug template with error checking -->
{% if not user %}
{{ raise('User object is required but not provided') }}
{% endif %}
{% if not user.permissions %}
{{ raise('User permissions not loaded') }}
{% endif %}
<!-- Development mode template validation -->
{% if config.DEBUG %}
{% if not posts %}
{{ raise('Posts data missing in template context') }}
{% endif %}
{% if posts|length == 0 %}
<!-- This won't raise an error, just show message -->
<p>No posts available</p>
{% endif %}
{% endif %}# Custom form field detection logic
class AdvancedForm(FlaskForm):
# Regular fields
title = StringField('Title')
content = TextAreaField('Content')
# Hidden fields
csrf_token = HiddenField()
user_id = HiddenField()
# Special fields
remember_me = BooleanField('Remember Me')
auto_publish = SwitchField('Auto-publish')
submit = SubmitField('Save')<!-- Template with advanced field handling -->
<form method="post">
<!-- Hidden fields first -->
{% for field in form if bootstrap_is_hidden_field(field) %}
{{ field() }}
{% endfor %}
<!-- Regular input fields -->
{% for field in form if not bootstrap_is_hidden_field(field) and field.type not in ['BooleanField', 'SwitchField', 'SubmitField'] %}
{{ render_field(field) }}
{% endfor %}
<!-- Boolean and switch fields in a group -->
<div class="mb-3">
<label class="form-label">Options</label>
{% for field in form if field.type in ['BooleanField', 'SwitchField'] %}
{{ render_field(field) }}
{% endfor %}
</div>
<!-- Submit button -->
{% for field in form if field.type == 'SubmitField' %}
{{ render_field(field) }}
{% endfor %}
</form># View combining multiple utilities
@app.route('/admin/users')
def admin_users():
users = User.query.all()
# Generate titles and customize
titles = get_table_titles(users, 'id', '#')
# Customize specific titles
title_dict = dict(titles)
title_dict['is_active'] = 'Status'
title_dict['last_login'] = 'Last Seen'
titles = list(title_dict.items())
return render_template('admin/users.html', users=users, titles=titles)# Using utilities with Flask-Admin
from flask_admin.contrib.sqla import ModelView
class UserAdmin(ModelView):
def on_model_change(self, form, model, is_created):
# Use raise_helper for validation in admin
if not model.email:
raise_helper('Email is required for user accounts')
super().on_model_change(form, model, is_created)
def scaffold_list_columns(self):
# Use get_table_titles for admin list view
columns = super().scaffold_list_columns()
# Customize column display based on auto-generated titles
return columns# Custom validator using utilities
def validate_required_fields(form):
"""Validate that all non-hidden fields have values"""
errors = []
for field in form:
if not is_hidden_field_filter(field) and hasattr(field, 'data'):
if field.data is None or field.data == '':
errors.append(f'{field.label.text} is required')
return errors
# Usage in view
@app.route('/submit', methods=['POST'])
def submit_form():
form = MyForm()
if form.validate_on_submit():
# Additional validation
validation_errors = validate_required_fields(form)
if validation_errors:
for error in validation_errors:
flash(error, 'error')
return render_template('form.html', form=form)
# Process form
return redirect(url_for('success'))
return render_template('form.html', form=form)bootstrap_is_hidden_field consistently for hidden field detectionget_table_titles for initial title generationraise_helper for development debugging onlyInstall with Tessl CLI
npx tessl i tessl/pypi-bootstrap-flask