CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-flask-appbuilder

Simple and rapid application development framework, built on top of Flask, with detailed security, auto CRUD generation, and comprehensive UI components.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

database-models.mddocs/

Database Models

SQLAlchemy integration with enhanced models, database interfaces, and application factory support providing flexible database management, model utilities, and seamless integration with Flask-AppBuilder's view and API systems.

Capabilities

Model Class

Base SQLAlchemy model class that provides enhanced functionality and integration with Flask-AppBuilder's features including JSON serialization and table configuration.

from flask_appbuilder.models.sqla import Model
from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey
from sqlalchemy.orm import relationship
import datetime

class Model(object):
    """
    Base model class for all Flask-AppBuilder models.
    Provides enhanced SQLAlchemy functionality.
    """
    
    def to_json(self):
        """
        Convert model instance to JSON-serializable dictionary.
        
        Returns:
        Dict with model data, handling relationships and special types
        """

# Base table configuration
__table_args__ = {"extend_existing": True}

# Usage example - Complete model definition
class Person(Model):
    __tablename__ = 'persons'
    
    # Primary key
    id = Column(Integer, primary_key=True)
    
    # Basic fields
    name = Column(String(150), unique=True, nullable=False)
    email = Column(String(120), unique=True, nullable=False)
    phone = Column(String(20))
    active = Column(Boolean, default=True)
    
    # Timestamps
    created_on = Column(DateTime, default=datetime.datetime.now)
    updated_on = Column(DateTime, default=datetime.datetime.now, 
                       onupdate=datetime.datetime.now)
    
    # Foreign key relationship
    department_id = Column(Integer, ForeignKey('departments.id'))
    department = relationship("Department", back_populates="persons")
    
    # String representation
    def __repr__(self):
        return self.name
    
    # Custom JSON serialization
    def to_json(self):
        return {
            'id': self.id,
            'name': self.name,
            'email': self.email,
            'active': self.active,
            'department': self.department.name if self.department else None,
            'created_on': self.created_on.isoformat() if self.created_on else None
        }

class Department(Model):
    __tablename__ = 'departments'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100), unique=True, nullable=False)
    description = Column(String(500))
    
    # Reverse relationship
    persons = relationship("Person", back_populates="department")
    
    def __repr__(self):
        return self.name

SQLA Class

Enhanced Flask-SQLAlchemy class providing Flask-AppBuilder integration, application factory support, and advanced session management capabilities.

from flask_appbuilder.models.sqla import SQLA
from flask_sqlalchemy import SQLAlchemy

class SQLA(SQLAlchemy):
    """
    Enhanced SQLAlchemy class with Flask-AppBuilder integration.
    Supports application factory pattern and custom configurations.
    """
    
    def make_declarative_base(self, model, metadata=None):
        """
        Create declarative base class with Flask-AppBuilder Model.
        
        Parameters:
        - model: Base model class (Model)
        - metadata: SQLAlchemy metadata instance
        
        Returns:
        Declarative base class
        """
    
    def get_tables_for_bind(self, bind=None):
        """
        Get tables for specific database bind.
        
        Parameters:  
        - bind: Database bind key
        
        Returns:
        List of table objects for the bind
        """
    
    def create_session(self, options):
        """
        Create custom database session with options.
        
        Parameters:
        - options: Session configuration dict
        
        Returns:
        SQLAlchemy session instance
        """

# Application factory usage
from flask import Flask
from flask_appbuilder import AppBuilder

# Create SQLA instance
db = SQLA()

def create_app():
    app = Flask(__name__)
    
    # Configure database
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    
    # Initialize SQLA with app
    db.init_app(app)
    
    # Initialize AppBuilder
    appbuilder = AppBuilder(app, db.session)
    
    return app

# Multiple database binds example
app.config['SQLALCHEMY_BINDS'] = {
    'users': 'sqlite:///users.db',
    'products': 'postgresql://user:pass@localhost/products'
}

class User(Model):
    __bind_key__ = 'users'
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    username = Column(String(80), unique=True, nullable=False)

class Product(Model):
    __bind_key__ = 'products' 
    __tablename__ = 'products'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)

Base Alias

Backward compatibility alias for the Model class to support legacy Flask-AppBuilder applications.

from flask_appbuilder.models.sqla import Base

# Base is an alias for Model - both are equivalent
Base = Model

# Legacy usage (still supported)
class LegacyModel(Base):
    __tablename__ = 'legacy_table'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))

# Modern usage (recommended)  
class ModernModel(Model):
    __tablename__ = 'modern_table'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))

SQLAInterface

Data model interface providing abstraction layer between models and Flask-AppBuilder views/APIs for database operations.

from flask_appbuilder.models.sqla.interface import SQLAInterface

class SQLAInterface:
    def __init__(self, obj, session=None):
        """
        Initialize interface for SQLAlchemy model.
        
        Parameters:
        - obj: SQLAlchemy model class
        - session: SQLAlchemy session (optional)
        """
    
    def get_query(self, filters=None, order_column='', order_direction=''):
        """
        Get SQLAlchemy query with filters and ordering.
        
        Parameters:
        - filters: List of filter objects
        - order_column: Column name for ordering  
        - order_direction: 'asc' or 'desc'
        
        Returns:
        SQLAlchemy Query object
        """
    
    def get_count(self, filters=None):
        """
        Get count of records matching filters.
        
        Parameters:
        - filters: List of filter objects
        
        Returns:
        Integer count of matching records
        """
    
    def get(self, pk):
        """
        Get single record by primary key.
        
        Parameters:
        - pk: Primary key value
        
        Returns:
        Model instance or None
        """
    
    def get_keys(self, lst):
        """
        Get primary key values from list of model instances.
        
        Parameters:
        - lst: List of model instances
        
        Returns:
        List of primary key values
        """
    
    def get_pk_value(self, item):
        """
        Get primary key value from model instance.
        
        Parameters:
        - item: Model instance
        
        Returns:
        Primary key value
        """
    
    def add(self, item):
        """
        Add model instance to database.
        
        Parameters:
        - item: Model instance to add
        
        Returns:
        Added model instance
        """
    
    def edit(self, item):
        """
        Update model instance in database.
        
        Parameters:
        - item: Model instance to update
        
        Returns:
        Updated model instance  
        """
    
    def delete(self, item):
        """
        Delete model instance from database.
        
        Parameters:
        - item: Model instance to delete
        
        Returns:
        Boolean success flag
        """

# Usage with views and APIs
from flask_appbuilder import ModelView, ModelRestApi

class PersonView(ModelView):
    datamodel = SQLAInterface(Person)
    list_columns = ['name', 'email', 'department']

class PersonApi(ModelRestApi):
    datamodel = SQLAInterface(Person)  
    list_columns = ['id', 'name', 'email']

# Custom interface usage
interface = SQLAInterface(Person)

# Get all active persons
filters = [FilterEqual('active', True)]
query = interface.get_query(filters=filters, order_column='name')
persons = query.all()

# Get count
count = interface.get_count(filters=filters)

# CRUD operations
new_person = Person(name="John Doe", email="john@example.com")
interface.add(new_person)

person = interface.get(1)
person.email = "newemail@example.com"  
interface.edit(person)

interface.delete(person)

Database Filters

Filter classes for building complex database queries with type-safe operations and support for various data types.

from flask_appbuilder.models.filters import BaseFilter, FilterEqual, FilterNotEqual, \
    FilterGreater, FilterSmaller, FilterStartsWith, FilterEndsWith, FilterContains, \
    FilterNotStartsWith, FilterNotEndsWith, FilterNotContains, FilterEqualFunction, \
    FilterInFunction, FilterConverter

# Basic filters
class FilterEqual(BaseFilter):
    """Exact match filter (column = value)"""
    
class FilterNotEqual(BaseFilter):
    """Not equal filter (column != value)"""
    
class FilterGreater(BaseFilter):
    """Greater than filter (column > value)"""
    
class FilterSmaller(BaseFilter):
    """Less than filter (column < value)"""

# String filters
class FilterStartsWith(BaseFilter):
    """Starts with filter (column LIKE 'value%')"""
    
class FilterEndsWith(BaseFilter):
    """Ends with filter (column LIKE '%value')"""
    
class FilterContains(BaseFilter):
    """Contains filter (column LIKE '%value%')"""
    
class FilterNotStartsWith(BaseFilter):
    """Does not start with filter"""
    
class FilterNotEndsWith(BaseFilter):
    """Does not end with filter"""
    
class FilterNotContains(BaseFilter):
    """Does not contain filter"""

# Function filters
class FilterEqualFunction(BaseFilter):
    """Filter using SQL function (FUNC(column) = value)"""
    
class FilterInFunction(BaseFilter):
    """Filter using IN with function"""

# Usage examples
from flask_appbuilder.models.sqla.filters import FilterEqual, FilterContains

# In ModelView or ModelRestApi
class PersonView(ModelView):
    datamodel = SQLAInterface(Person)
    
    # Base filters applied to all queries
    base_filters = [
        ['active', FilterEqual, True],           # active = True
        ['name', FilterContains, 'John'],        # name LIKE '%John%'
        ['created_on', FilterGreater, datetime.date(2023, 1, 1)]  # created_on > '2023-01-01'
    ]
    
    # Available search filters
    search_filters = {
        'name': [FilterEqual, FilterContains, FilterStartsWith],
        'email': [FilterEqual, FilterContains],
        'active': [FilterEqual],
        'created_on': [FilterEqual, FilterGreater, FilterSmaller]
    }

# Custom filter example
class FilterActiveInLastDays(BaseFilter):
    name = "Active in Last N Days"
    arg_name = "days"
    
    def apply(self, query, value):
        cutoff_date = datetime.datetime.now() - datetime.timedelta(days=int(value))
        return query.filter(self.column >= cutoff_date)

# Advanced filtering with relationships
class PersonView(ModelView):
    datamodel = SQLAInterface(Person)
    
    # Filter by related model fields
    base_filters = [
        ['department.name', FilterEqual, 'Engineering'],  # Join filter
        ['department.active', FilterEqual, True]           # Related field filter
    ]

Model Mixins and Utilities

Utility mixins and helper functions for common model patterns and enhanced functionality.

# Audit mixin for tracking changes
from flask_appbuilder.models.mixins import AuditMixin
from flask_appbuilder.models.decorators import renders
import datetime

class AuditMixin(object):
    """Mixin for audit trail fields."""
    
    created_on = Column(DateTime, default=datetime.datetime.now, nullable=False)
    changed_on = Column(DateTime, default=datetime.datetime.now, 
                       onupdate=datetime.datetime.now, nullable=False)
    created_by_fk = Column(Integer, ForeignKey('ab_user.id'), nullable=False)
    changed_by_fk = Column(Integer, ForeignKey('ab_user.id'), nullable=False)
    
    created_by = relationship("User", foreign_keys=[created_by_fk])
    changed_by = relationship("User", foreign_keys=[changed_by_fk])

# File mixin for file uploads
class FileColumn(Model):
    """Model for file storage."""
    
    id = Column(Integer, primary_key=True)
    file = Column(FileColumn, nullable=False)

# Image mixin  
class ImageColumn(Model):
    """Model for image storage."""
    
    id = Column(Integer, primary_key=True)
    image = Column(ImageColumn, nullable=False)

# Usage with audit mixin
class AuditedPerson(Model, AuditMixin):
    __tablename__ = 'audited_persons'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(150), nullable=False)
    email = Column(String(120), nullable=False)

# Custom field rendering
@renders('name')
def render_name(self):
    """Custom rendering for name field."""
    return f"<strong>{self.name}</strong>"

# Model validation  
from marshmallow import ValidationError

class Person(Model):
    __tablename__ = 'persons'
    
    id = Column(Integer, primary_key=True)
    email = Column(String(120), nullable=False)
    
    def validate_email(self, email):
        """Custom email validation."""
        if not email or '@' not in email:
            raise ValidationError("Invalid email address")

# Soft delete mixin
class SoftDeleteMixin(object):
    """Mixin for soft delete functionality."""
    
    deleted = Column(Boolean, default=False, nullable=False)
    deleted_on = Column(DateTime)
    
    def soft_delete(self):
        """Mark record as deleted."""
        self.deleted = True
        self.deleted_on = datetime.datetime.now()

class SoftDeletedModel(Model, SoftDeleteMixin):
    __tablename__ = 'soft_deleted'
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    
    # Override queries to exclude deleted records
    @classmethod
    def query_active(cls):
        return cls.query.filter(cls.deleted == False)

Install with Tessl CLI

npx tessl i tessl/pypi-flask-appbuilder

docs

actions-hooks.md

charts.md

cli-tools.md

constants-exceptions.md

core-framework.md

database-models.md

forms-fields.md

index.md

rest-api.md

security.md

views-crud.md

tile.json