Add SQLAlchemy support to your Flask application.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Declarative model base classes with automatic table naming, bind key support, and Flask integration features. Includes table creation utilities and metadata management.
The declarative base class for defining database models with Flask-SQLAlchemy enhancements.
class Model:
"""
Base class for declarative database models.
Provides Flask-SQLAlchemy specific functionality including
automatic table naming and query property integration.
"""
__fsa__: SQLAlchemy # Internal reference to extension
query_class: type[Query] # Query class for model queries
query: Query # Query property for this model
def __repr__(self) -> str:
"""String representation showing model name and primary key."""Internal class that implements the query property on model classes.
class _QueryProperty:
"""
A class property that creates a query object for a model.
This is the internal implementation behind Model.query. It creates
a Query instance bound to the model class and current session.
Note: This is an internal class but is documented for completeness
since users interact with it through Model.query.
"""
def __get__(self, obj: Model | None, cls: type[Model]) -> Query:
"""
Create and return a Query instance for the model class.
Parameters:
- obj: Model instance (unused, queries are class-level)
- cls: Model class to create query for
Returns:
Query instance bound to the model class and current session
"""Enhanced Table class that automatically selects metadata based on bind keys.
class Table(sa.Table):
def __init__(
self,
name: str,
*args: sa_sql_schema.SchemaItem,
bind_key: str | None = None,
**kwargs: Any,
) -> None:
"""
Create a table with automatic metadata selection.
Parameters:
- name: Table name
- args: Columns, constraints, and other schema items
- bind_key: Bind key to select appropriate metadata
- kwargs: Additional table arguments
"""Mixins that provide automatic metadata selection based on model bind keys.
class BindMixin:
"""
DeclarativeBase mixin to set model metadata based on __bind_key__.
For SQLAlchemy 2.x declarative base classes.
"""
__fsa__: SQLAlchemy
metadata: sa.MetaData
@classmethod
def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
"""Set metadata based on __bind_key__ if present."""
class BindMetaMixin(type):
"""
Metaclass mixin for automatic bind key metadata assignment.
For SQLAlchemy 1.x declarative metaclass usage.
"""
def __init__(
cls,
name: str,
bases: tuple[type, ...],
d: dict[str, Any],
**kwargs: Any,
) -> None:
"""Set metadata based on __bind_key__ during class creation."""Mixins that provide automatic table name generation from class names.
class NameMixin:
"""
DeclarativeBase mixin for automatic __tablename__ generation.
Converts CamelCase model names to snake_case table names.
For SQLAlchemy 2.x declarative base classes.
"""
@classmethod
def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
"""Generate __tablename__ if not explicitly set."""
@classmethod
def __table_cls__(cls, *args: Any, **kwargs: Any) -> sa.Table | None:
"""Determine final table object for the model."""
class NameMetaMixin(type):
"""
Metaclass mixin for automatic table naming.
For SQLAlchemy 1.x declarative metaclass usage.
"""
def __init__(
cls,
name: str,
bases: tuple[type, ...],
d: dict[str, Any],
**kwargs: Any,
) -> None:
"""Generate __tablename__ during class creation."""
def __table_cls__(cls, *args: Any, **kwargs: Any) -> sa.Table | None:
"""Determine final table object for the model."""Combined metaclasses that provide both bind key and naming functionality.
class DefaultMeta(BindMetaMixin, NameMetaMixin, sa_orm.DeclarativeMeta):
"""
SQLAlchemy declarative metaclass with __bind_key__ and __tablename__ support.
Combines bind key metadata selection and automatic table naming.
"""
class DefaultMetaNoName(BindMetaMixin, sa_orm.DeclarativeMeta):
"""
SQLAlchemy declarative metaclass with __bind_key__ support only.
Provides bind key functionality without automatic table naming.
"""Helper functions for table naming and model configuration.
def should_set_tablename(cls: type) -> bool:
"""
Determine whether __tablename__ should be generated for a model.
Parameters:
- cls: Model class to check
Returns:
True if __tablename__ should be auto-generated
"""
def camel_to_snake_case(name: str) -> str:
"""
Convert CamelCase name to snake_case.
Parameters:
- name: CamelCase string to convert
Returns:
snake_case version of the name
"""class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
# Table name automatically generated as 'user'from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
db = SQLAlchemy(app, model_class=Base)
class User(db.Model):
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
username: Mapped[str] = mapped_column(db.String(80), unique=True)class User(db.Model):
__bind_key__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
class Log(db.Model):
__bind_key__ = 'logs'
id = db.Column(db.Integer, primary_key=True)
message = db.Column(db.Text)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)class UserAccount(db.Model):
__tablename__ = 'accounts' # Override automatic naming
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100))users_table = db.Table(
'users',
db.Column('id', db.Integer, primary_key=True),
db.Column('name', db.String(50)),
bind_key='users' # Specify bind key for metadata selection
)# Disable automatic table naming globally
db = SQLAlchemy(app, disable_autonaming=True)
class User(db.Model):
__tablename__ = 'users' # Must specify explicitly
id = db.Column(db.Integer, primary_key=True)All models automatically get a query property for database queries:
# Query using the model's query property
user = User.query.get(1)
users = User.query.filter_by(active=True).all()
# The query property uses the configured query_class
users = User.query.filter(User.age > 18).paginate(page=1, per_page=10)Install with Tessl CLI
npx tessl i tessl/pypi-flask-sqlalchemy