Skip to content

Repository files navigation

sqlmodel-toolkit

A toolkit for cleaner SQLModel queries with fluent API, Model base class, and engine management.

sqlmodel-toolkit provides a system for working with SQLModel that simplifies database interactions through a fluent query interface, removing boilerplate and making your data layer code more readable and maintainable.

Features

  • Chainable Query API: Chain query methods naturally: .where().order_by().limit().all()
  • Class-level Query Methods: Call queries directly on your model: User.find(1), User.where(active=True).all()
  • Simplified Engine Management: Set once, use everywhere with Model.set_engine()
  • Eager Loading: Prevent N+1 queries with .with_() relationship loading
  • Type-Safe: Full type hints for excellent IDE support
  • Zero Dependencies Beyond SQLModel: Minimal surface area

Installation

pip install git+https://github.com/Code-Society-Lab/sqlmodel-toolkit.git

Quick Start

1. Define your models

fromsqlmodelimportField, Relationshipfromsqlmodel_toolkitimportModelclassUser(Model):
id: int|None=Field(default=None, primary_key=True)
name: stremail: stractive: bool=Trueposts: list["Post"] =Relationship(back_populates="author")
classPost(Model):
id: int|None=Field(default=None, primary_key=True)
title: strauthor_id: int=Field(foreign_key="user.id")
author: User=Relationship(back_populates="posts")

2. Configure the engine

fromsqlmodelimportcreate_enginefromsqlmodel_toolkitimportModelengine=create_engine("sqlite:///database.db")
Model.set_engine(engine)
# Create tablesSQLModel.create_all(engine)

3. Use your models

# Createuser=User.create(name="Alice", email="alice@example.com")
# Find by primary keyuser=User.find(1)
# Find with conditionsuser=User.find_by(email="alice@example.com")
# Query with chainable methodsactive_users=User.where(User.active==True).all()
# Order and limitrecent_users=User.order_by(User.id.desc()).limit(10).all()
# Combine conditionsadmin_users=User.where(User.active==True).where(User.role=="admin").all()
# Or use keyword arguments for equalityactive_admins=User.where(active=True, role="admin").all()
# Exclude recordsinactive_users=User.not_(active=True).all()
# Avoid N+1 queries with eager loadingusers_with_posts=User.with_("posts").all()
# Count resultstotal=User.where(active=True).count()
# Get exactly one resultuser=User.where(email="alice@example.com").one()
# Updateuser.update(name="Alice Smith", active=False)
# Reload from databaseuser.reload()
# Deleteuser.delete()

API Reference

Query Methods

All query methods return Query for chaining, except terminal methods.

where(*conditions, **kwargs) -> Query

Add filtering conditions to the query.

# Using SQLAlchemy expressionsUser.where(User.age>18, User.active==True)
# Using keyword arguments for equalityUser.where(name="Alice", active=True)
# Mix both stylesUser.where(User.age>18, active=True)

not_(*conditions, **kwargs) -> Query

Negate filtering conditions (exclude records matching criteria).

# Exclude inactive usersUser.not_(active=False).all()
# Exclude specific usersUser.not_(name="Alice").all()

with_(*relationships) -> Query

Eagerly load relationships to prevent N+1 queries.

# Load single relationshipusers=User.with_("posts").all()
# Load multiple relationshipsusers=User.with_("posts", "comments").all()

order_by(*args, **kwargs) -> Query

Order results by one or more columns.

# Using SQLAlchemy expressionsUser.order_by(User.name)
User.order_by(User.created_at.desc())
# Using keyword argumentsUser.order_by(name="asc", age="desc")

limit(count: int) -> Query

Limit the number of results.

User.limit(10).all()

offset(count: int) -> Query

Skip a given number of records (useful for pagination).

User.offset(20).limit(10).all() # Get items 21-30

distinct() -> Query

Return only unique records.

User.distinct().all()

Terminal Methods

These execute the query and return results:

  • all() -> List[T] — Return all matching records as a list
  • first() -> T | None — Return the first matching record or None
  • one() -> T — Return exactly one result (raises if not found)
  • count() -> int — Return the count of matching records

Model Methods

find(value) -> T | None

Find a record by its primary key.

user=User.find(1)

find_by(**kwargs) -> T | None

Find the first record matching the provided conditions.

user=User.find_by(email="alice@example.com")
user=User.find_by(name="Alice", active=True)

create(**kwargs) -> T

Create and save a new record.

user=User.create(name="Alice", email="alice@example.com")

query() -> Query

Get a new query object for manual query building (rarely needed).

User.query().where(User.active==True).all()

Instance Methods

save() -> Self

Save the instance to the database.

user=User(name="Alice")
user.save()

update(**kwargs) -> Self

Update attributes and save to the database.

user.update(name="Alice Smith", active=False)

reload() -> Self

Reload the instance from the database, discarding unsaved changes.

user.reload()

delete() -> None

Delete the record from the database.

user.delete()

Requirements

  • Python 3.10+
  • sqlmodel 0.0.38+

License

This project is licensed under the terms of MIT license.

Contributing

Contributions welcome! Please feel free to submit issues and pull requests.

About

A toolkit for cleaner SQLModel queries with fluent API, Model base class, and engine management

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages