CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-bootstrap-flask

Bootstrap 4 & 5 helper for Flask projects providing Jinja macros for forms, tables, navigation, and utilities.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

table-rendering.mddocs/

Table Rendering

Data table rendering with Bootstrap styling, supporting CRUD actions, responsive design, pagination integration, and flexible column formatting options for displaying data collections.

Capabilities

Complete Table Rendering

Render data collections as Bootstrap-styled tables with optional CRUD actions and extensive customization.

def render_table(data, titles=None, primary_key='id', primary_key_title='#',
                caption=None, table_classes=None, header_classes=None,
                body_classes=None, responsive=False, responsive_class='table-responsive',
                safe_columns=None, urlize_columns=None, model=None,
                show_actions=False, actions_title='Actions', custom_actions=None,
                view_url=None, edit_url=None, delete_url=None, new_url=None,
                action_pk_placeholder=':id'):
    """
    Render a data collection as a Bootstrap table.
    
    Args:
        data (list): List of objects/dicts to display in table
        titles (list): List of (field_name, display_title) tuples for columns
        primary_key (str): Primary key field name (default: 'id')
        primary_key_title (str): Display title for primary key column (default: '#')
        caption (str): Table caption text
        table_classes (str): CSS classes for table element
        header_classes (str): CSS classes for table header
        body_classes (str): CSS classes for table body
        responsive (bool): Enable responsive table wrapper
        responsive_class (str): CSS class for responsive wrapper
        safe_columns (list): Column names to render as safe HTML
        urlize_columns (list): Column names to convert URLs to links
        model: SQLAlchemy model class for automatic title detection
        show_actions (bool): Display CRUD action buttons
        actions_title (str): Title for actions column
        custom_actions (list): Custom action button definitions
        view_url (str): URL pattern for view action
        edit_url (str): URL pattern for edit action  
        delete_url (str): URL pattern for delete action
        new_url (str): URL for new record creation
        action_pk_placeholder (str): Placeholder for primary key in URLs
        
    Returns:
        Rendered HTML table with Bootstrap styling
        
    Data Sources:
        - List of dictionaries
        - List of SQLAlchemy model instances
        - List of custom objects with attributes
        
    URL Patterns:
        - Use :id placeholder for primary key substitution
        - Example: '/users/:id/edit' becomes '/users/123/edit'
    """

Table Title Generation

Automatically generate table column titles from SQLAlchemy models.

def get_table_titles(data, primary_key, primary_key_title):
    """
    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
        
    Returns:
        list: List of (field_name, display_title) tuples
        
    Behavior:
        - Extracts column names from SQLAlchemy model metadata
        - Converts snake_case to Title Case (user_name -> User Name)
        - Excludes fields starting with underscore
        - Sets primary key title as specified
        
    Example:
        For User model with columns: id, first_name, last_name, email
        Returns: [('id', '#'), ('first_name', 'First Name'), 
                 ('last_name', 'Last Name'), ('email', 'Email')]
    """

Internal URL Building

Internal helper for constructing action URLs with dynamic parameters.

def build_url(record, endpoint, url_tuples, model, pk_field):
    """
    Internal helper to build URLs for table actions.
    
    Args:
        record: Data record (dict or object)
        endpoint (str): Flask endpoint or URL pattern
        url_tuples (list): URL parameter tuples
        model: SQLAlchemy model class
        pk_field (str): Primary key field name
        
    Returns:
        str: Constructed URL with substituted parameters
        
    Note: This is an internal helper used by render_table
    """

Table Features

Data Source Support

Bootstrap-Flask tables support multiple data source types:

Dictionary Lists

data = [
    {'id': 1, 'name': 'John Doe', 'email': 'john@example.com'},
    {'id': 2, 'name': 'Jane Smith', 'email': 'jane@example.com'},
]

SQLAlchemy Model Instances

users = User.query.all()  # List of SQLAlchemy model instances

Custom Objects

class Person:
    def __init__(self, id, name, email):
        self.id = id
        self.name = name  
        self.email = email

data = [Person(1, 'John', 'john@example.com')]

Column Configuration

Manual Title Definition

titles = [
    ('id', '#'),
    ('first_name', 'First Name'),
    ('last_name', 'Last Name'),
    ('email', 'Email Address'),
    ('created_at', 'Date Created')
]

Automatic Title Generation

# For SQLAlchemy models - automatically generates titles
titles = get_table_titles(users, 'id', '#')

CRUD Actions

Bootstrap-Flask provides built-in CRUD action buttons:

Standard Actions

  • View: Display record details
  • Edit: Modify record
  • Delete: Remove record
  • New: Create new record

Action URL Patterns

# URL patterns with :id placeholder
view_url = '/users/:id'
edit_url = '/users/:id/edit'  
delete_url = '/users/:id/delete'
new_url = '/users/new'

Custom Actions

custom_actions = [
    {
        'title': 'Activate',
        'url': '/users/:id/activate',
        'classes': 'btn-success btn-sm'
    },
    {
        'title': 'Archive', 
        'url': '/users/:id/archive',
        'classes': 'btn-warning btn-sm'
    }
]

Column Formatting

Safe HTML Columns

Render column content as safe HTML without escaping:

safe_columns = ['description', 'notes']  # Won't escape HTML tags

URL Columns

Automatically convert URLs to clickable links:

urlize_columns = ['website', 'blog_url']  # Convert to <a> tags

Responsive Design

Tables can be made responsive to handle overflow on small screens:

# Enable responsive wrapper
responsive = True
responsive_class = 'table-responsive-md'  # Responsive on medium screens and below

Usage Examples

Basic Table

# View function
@app.route('/users')
def users():
    users = [
        {'id': 1, 'name': 'John Doe', 'email': 'john@example.com'},
        {'id': 2, 'name': 'Jane Smith', 'email': 'jane@example.com'},
    ]
    return render_template('users.html', users=users)
<!-- Template -->
{% from 'base/table.html' import render_table %}

<div class="container">
    <h2>Users</h2>
    {{ render_table(users) }}
</div>

Table with Custom Styling

{{ render_table(users,
    table_classes="table table-striped table-hover table-bordered",
    header_classes="table-dark",
    caption="List of registered users"
) }}

Table with CRUD Actions

{{ render_table(users,
    show_actions=True,
    view_url="/users/:id",
    edit_url="/users/:id/edit", 
    delete_url="/users/:id/delete",
    new_url="/users/new",
    actions_title="Operations"
) }}

SQLAlchemy Model Table

# Model
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(50))
    last_name = db.Column(db.String(50))
    email = db.Column(db.String(120))
    created_at = db.Column(db.DateTime)

# View
@app.route('/users')
def users():
    users = User.query.all()
    titles = get_table_titles(users, 'id', 'User ID')
    return render_template('users.html', users=users, titles=titles)
{{ render_table(users, titles=titles, model=User, show_actions=True) }}

Responsive Table with Custom Columns

{{ render_table(products,
    titles=[
        ('id', 'ID'),
        ('name', 'Product Name'),
        ('description', 'Description'),
        ('price', 'Price'),
        ('website', 'Website')
    ],
    responsive=True,
    responsive_class="table-responsive-lg",
    safe_columns=['description'],
    urlize_columns=['website'],
    table_classes="table table-sm"
) }}

Table with Custom Actions

{{ render_table(orders,
    show_actions=True,
    custom_actions=[
        {
            'title': 'Ship',
            'url': '/orders/:id/ship',
            'classes': 'btn-success btn-sm'
        },
        {
            'title': 'Cancel',
            'url': '/orders/:id/cancel', 
            'classes': 'btn-danger btn-sm'
        },
        {
            'title': 'Invoice',
            'url': '/orders/:id/invoice',
            'classes': 'btn-info btn-sm'  
        }
    ]
) }}

Table with Pagination Integration

# View with pagination
@app.route('/users')
def users():
    page = request.args.get('page', 1, type=int)
    users = User.query.paginate(
        page=page, per_page=10, error_out=False
    )
    return render_template('users.html', users=users)
{% from 'base/table.html' import render_table %}
{% from 'base/pagination.html' import render_pagination %}

{{ render_table(users.items, show_actions=True) }}
{{ render_pagination(users) }}

Advanced Configuration

{{ render_table(data,
    titles=custom_titles,
    primary_key='user_id',
    primary_key_title='User ID',
    table_classes="table table-striped table-hover",
    header_classes="table-primary", 
    body_classes="small",
    responsive=True,
    responsive_class="table-responsive-md",
    safe_columns=['bio', 'notes'],
    urlize_columns=['website', 'linkedin'],
    show_actions=True,
    actions_title="Manage",
    view_url="/users/:id/profile",
    edit_url="/users/:id/settings",
    delete_url="/admin/users/:id/delete",
    new_url="/users/register",
    action_pk_placeholder=':id'
) }}

Empty Table Handling

{% if data %}
    {{ render_table(data) }}
{% else %}
    <div class="alert alert-info">
        <h4>No Records Found</h4>
        <p>There are currently no records to display.</p>
        <a href="{{ url_for('new_record') }}" class="btn btn-primary">
            Add New Record
        </a>
    </div>
{% endif %}

Configuration Variables

Table rendering respects several Flask configuration variables:

# Table action button titles (configurable)
app.config['BOOTSTRAP_TABLE_VIEW_TITLE'] = 'View'
app.config['BOOTSTRAP_TABLE_EDIT_TITLE'] = 'Edit'  
app.config['BOOTSTRAP_TABLE_DELETE_TITLE'] = 'Delete'
app.config['BOOTSTRAP_TABLE_NEW_TITLE'] = 'New'

These configuration values are used as default titles for CRUD action buttons and can be overridden at the template level.

Install with Tessl CLI

npx tessl i tessl/pypi-bootstrap-flask

docs

extension-setup.md

form-rendering.md

index.md

navigation.md

pagination.md

python-utilities.md

table-rendering.md

utilities.md

tile.json