flask-modelkit
Composable model mixins for Flask-SQLAlchemy.
Documentation: anoziechibuike.github.io/FlaskModelKit
⭐ If flask-modelkit saves you from writing another base model, star it on GitHub. It helps other Flask developers find it.
Formerly published as
FlaskSQLAlchemyBaseModel. See Migrating from FlaskSQLAlchemyBaseModel.
Most Flask projects end up writing the same base model: a UUID primary key, created_at/updated_at, save(), to_dict(), maybe soft delete. Each copy has its own subtle bugs. This package gives you those pieces as small mixins that you combine per model. The edge cases are handled and tested.
class Post(UUIDMixin, TimestampMixin, SoftDeleteMixin, CRUDMixin, SerializerMixin, db.Model):
title = db.Column(db.String(200), nullable=False)
Features
- Pick what you need. UUID or integer keys, timestamps, soft delete, CRUD helpers and serialisation are separate mixins.
BaseModelMixinbundles the common set. - Soft delete that actually hides rows. Deleted rows are filtered out of every ORM query: helpers,
Model.query,db.select(),session.get()and relationship loads. - Hidden and protected fields. Mark a column
hidden(never sent to the client),protected(never set from client input) or both, right where you declare it. - Safe updates.
update(request.json)only sets mapped columns and never touchesid, timestamps or any protected field. - Create from request data in one line.
create_or_abort(request.json)drops unsafe keys, answers 400 naming every missing field, and 409 naming a duplicate unique field. - Safe serialisation.
to_dict()never outputs hidden fields (such as password hashes), limits relationship depth, never loops onback_populates, and returns JSON-ready output on request. - Efficient queries. Counts and existence checks run in SQL. Pagination is stably ordered.
- Migration-friendly. Defaults are generated in Python, so Flask-Migrate/Alembic produces clean migrations with no spurious diffs.
- Typed. Ships
py.typed, and class methods return your model type. - Works with your own
db. No globalSQLAlchemy()is forced on you.
Requires Python 3.10+, Flask 3, Flask-SQLAlchemy 3.1+ and SQLAlchemy 2.0.16+.
Install
pip install flask-modelkit
Quick start
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_modelkit import BaseModelMixin, protected_column, secret_column
db = SQLAlchemy()
class User(BaseModelMixin, db.Model): # mixins go before db.Model
name = db.Column(db.String(50), nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
is_admin = protected_column(db.Boolean, default=False) # input can't set it
password_hash = secret_column(db.String(200)) # never read out, never written in
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///app.db"
db.init_app(app)
with app.app_context():
db.create_all() # or Flask-Migrate, see https://anoziechibuike.github.io/FlaskModelKit/#migrations
@app.post("/users")
def create_user():
# 400 if name/email are missing, 409 if the email is taken, unknown keys dropped
user = User.create_or_abort(request.get_json(silent=True))
return jsonify(user.to_dict(json_safe=True)), 201
@app.patch("/users/<id>")
def update_user(id):
user = User.get_or_404(id)
user.update(request.json) # id, timestamps, is_admin, password_hash can't be set
return jsonify(user.to_dict(json_safe=True))
@app.get("/users")
def list_users():
page = User.paginate(page=request.args.get("page", 1, type=int), per_page=20)
page["items"] = [u.to_dict(json_safe=True) for u in page["items"]]
return jsonify(page)
Don't have a db yet? Use the bundled one:
from flask_modelkit import db, BaseModel
class User(BaseModel):
name = db.Column(db.String(50))
Documentation
The full documentation is at anoziechibuike.github.io/FlaskModelKit.
| Guide | |
|---|---|
| Quick start | A complete app in four steps |
| Mixins | Every mixin, an interactive builder, and the one ordering rule |
| Creating & updating | create, create_or_abort, save, update, transactions |
| Reading & filtering | get, filters, counts, pagination, custom queries |
| Hidden vs protected | Controlling what goes out to and comes in from the client |
| Serialisation | to_dict(), depth, JSON output |
| Soft delete | How rows are hidden, including deleted rows, restoring |
| Migrations | Flask-Migrate/Alembic, adding mixins to existing tables |
| Project examples | A blog API, a shop checkout, lookup tables |
| API reference | Every public name |
Use with AI agents
AI coding assistants don't know this package's rules: mixins before db.Model, create_or_abort() for request data, secret_column() for password hashes. AGENT.md spells them out. Add it to your project once, from the project root:
# Claude Code: save it, then import it from CLAUDE.md
mkdir -p .claude && curl -fsSL https://anoziechibuike.github.io/FlaskModelKit/AGENT.md -o .claude/flask-modelkit.md
echo "@.claude/flask-modelkit.md" >> CLAUDE.md
# Cursor: a project rule attached to Python files
mkdir -p .cursor/rules
{ printf -- '---\ndescription: How to use flask-modelkit models, fields and endpoints\nglobs: **/*.py\nalwaysApply: false\n---\n\n'
curl -fsSL https://anoziechibuike.github.io/FlaskModelKit/AGENT.md; } > .cursor/rules/flask-modelkit.mdc
# GitHub Copilot: path-specific instructions for Python files
mkdir -p .github/instructions
{ printf -- '---\napplyTo: "**/*.py"\n---\n\n'
curl -fsSL https://anoziechibuike.github.io/FlaskModelKit/AGENT.md; } > .github/instructions/flask-modelkit.instructions.md
# Codex, Jules, Amp, Zed and other AGENTS.md readers (Gemini CLI: GEMINI.md)
curl -fsSL https://anoziechibuike.github.io/FlaskModelKit/AGENT.md >> AGENTS.md
In a chat assistant, say: "Read https://anoziechibuike.github.io/FlaskModelKit/AGENT.md and follow it for all flask-modelkit code." To pin the rules to your installed version, download from the release tag instead, for example https://raw.githubusercontent.com/AnozieChibuike/FlaskModelKit/v1.0.0/AGENT.md. See Use with AI agents for details.
Migrating from FlaskSQLAlchemyBaseModel
flask-modelkit 1.0 continues FlaskSQLAlchemyBaseModel under a new name.
pip uninstall FlaskSQLAlchemyBaseModel
pip install flask-modelkit
Then replace the import:
# before
from flasksqlalchemybasemodel import BaseModel, db
# after
from flask_modelkit import BaseModel, db
The old flasksqlalchemybasemodel.src module is gone; import from flask_modelkit directly. The columns the mixins create are unchanged, so no database migration is needed. See CHANGELOG.md for everything else that changed.
Development
pip install -e . pytest alembic
pytest
CI runs the suite on Python 3.10–3.13 and against the minimum supported dependency versions.
Star history
More numbers, including downloads, live on the Community & stats page.
License
MIT
Metadata
Release files for flask-modelkit 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| flask_modelkit-1.0.0.tar.gz | 15.6 kB | With provenance | Details for flask_modelkit-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| flask_modelkit-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for flask_modelkit-1.0.0-py3-none-any.whl |
Total release size: 29.8 kB
Release files / flask_modelkit-1.0.0.tar.gz
| Download URL | flask_modelkit-1.0.0.tar.gz |
|---|---|
| Size | 15.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f7c45d2bf073e50b45da0f6f0c0d9a4ebddefc86163f60c86e483f5c3dd626a
|
|
BLAKE2b-256 checksum How to use checksums |
96393ad375de57e8170eb63c029d93cf074b7c307d8d159d3fa8ee804a71b2dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logRelease files / flask_modelkit-1.0.0-py3-none-any.whl
| Download URL | flask_modelkit-1.0.0-py3-none-any.whl |
|---|---|
| Size | 14.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ed7d5d344a3620302eb3238930b8c4b249579081c02e04a286b278afe86c5f1b
|
|
BLAKE2b-256 checksum How to use checksums |
5fac12faf15e6f676bb4423ac7dfd83edc1d9a376acdb8af6d05e7f11c386991
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logSecurity for flask-modelkit 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for flask_modelkit-1.0.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.