Skip to main content

Simplie and Fast utility for SQLModel/SQLAlchemy and Alembic

Project description

FastSQLModel

Overview

FastSQLModel is a utility for simplifying the process of using SQLModel/SQLAlchemy and Alembic. It provides a CLI for initializing and managing Alembic migrations, and a set of tools for working with SQLModel and SQLAlchemy models.

Features

  • CLI for Alembic: FastSQLModel provides a CLI for initializing and managing Alembic migrations.
  • SQLModel and SQLAlchemy Models: FastSQLModel provides a set of tools for working with SQLModel and SQLAlchemy models.
  • Database Management: FastSQLModel provides a set of tools for managing the database, including creating, dropping, and querying the database.

Developer Guide

Install FastSQLModel in Development

If you want to make changes to the package, you can install it in development mode. This project uses nbdev for development, so you can make changes to the code and documentation in the notebooks under the nbs/ directory. To find out more about amazing nbdev, visit the nbdev documentation.

To make changes to the package, you can install it in development mode.

# make sure FastSQLModel package is installed in development mode
$ pip install -e .

# make changes under nbs/ directory
# ...

# compile to have changes apply to FastSQLModel
$ nbdev_prepare

Usage

Installation

Install latest from the GitHub repository:

$ pip install git+https://github.com/ndendic/FastSQLModel.git

or from conda

$ conda install -c ndendic FastSQLModel

or from pypi

$ pip install FastSQLModel

To establish a connection to the database, please specify the DATABASE_URL in the .env file.

Documentation

Documentation can be found hosted on this GitHub repository’s pages. Additionally you can find package manager specific guidelines on conda and pypi respectively.

How to use

Create your first model

To create your first model, you can can import the BaseTable class from the FastSQLModel.db module and create a new model by subclassing it. BaseTable is a subclass of SQLModel, so it has all the same features, but it also has a few extra features to help with some standard db operations and 3 extra fields: - id: primary key, default to a uuid4 - created_at: datetime, default to now - updated_at: datetime, default to now, and updated on every save

class BaseTable(SQLModel):
    model_config = ConfigDict(json_encoders={datetime: lambda dt: dt.isoformat()})
    id: UUID = Field(default_factory=uuid4, primary_key=True)
    created_at: datetime = Field(
        default_factory=utc_now,
        sa_type= sa.DateTime(timezone=True),
        sa_column_kwargs={"server_default": sa.func.now()},
        nullable=False,
        title="Created At",
        schema_extra={"icon": "clock", "input_type": "datetime"},
    )
    updated_at: datetime = Field(
        default_factory=utc_now,
        sa_type=sa.DateTime(timezone=True),
        sa_column_kwargs={
            "server_default": sa.func.now(),
            "server_onupdate": sa.func.now(),
        },
        # onupdate=utc_now,
        nullable=False,
        title="Updated At",
        schema_extra={"icon": "clock", "input_type": "datetime"},
    )

Here is an example of how to create a new model using BaseTable

# users.py
from typing import Optional
from sqlmodel import Field
from datetime import datetime
from FastSQLModel.db import BaseTable

class User(BaseTable, table=True):
    name: Optional[str] = Field(nullable=True)
    email: str = Field(nullable=False)
    password: str = Field(nullable=False)
    joined_at: datetime = Field(nullable=False)

Now that you have created your first model, you can use the CLI to initialize and manage Alembic project.

$ fastmodel init

This will create a new Alembic project in the current directory, and create a new .alembic.ini file.

  1. Then make sure to add your models to the migrations/env.py file before running migrations.
# migrations/env.py
from users import User
# ...
  1. Now you can run migrations to prepare the database for your models.
$ fastmodel migrations
  1. And now you can migrate your models to the database.
$ fastmodel migrate

Let’s see how this works

Initialization:

# !fastmodel init

Making migrations

!fastmodel migrations
Generating Alembic migration with message: Pushing changes
DATABASE_URL sqlite:///test.db
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
  Generating /home/ndendic/WebDev/FastSQLModel/nbs/migrations/versions/4d4567890
  1bc_pushing_changes.py ...  done
Migration created successfully!

Migrating changes

!fastmodel migrate
Applying database migrations...
DATABASE_URL sqlite:///test.db
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade 5441880ad0e3 -> 4d45678901bc, Pushing changes
Migrations applied successfully!

Once our table is migrated, we can start adding some data like this.

user = User(name="Homer Simpson", email="homer@simpson.com", password="password", joined_at=datetime.now())
user.save()
user.model_dump()
{'name': 'Homer Simpson',
 'email': 'homer@simpson.com',
 'password': 'password',
 'joined_at': datetime.datetime(2024, 12, 19, 16, 2, 4, 408489),
 'id': UUID('f4ff6c91-8fcf-44a8-9874-cf2535a8d10c'),
 'created_at': datetime.datetime(2024, 12, 19, 15, 2, 4, 413702, tzinfo=datetime.timezone.utc),
 'updated_at': datetime.datetime(2024, 12, 19, 15, 2, 4, 413744, tzinfo=datetime.timezone.utc)}

Let’s get our user by id

homer = User.get(user.id)
if homer:
    print(f"Name: {homer.name}, Email: {homer.email}")
else:
    print("User not found")
Name: Homer Simpson, Email: homer@simpson.com

Or by alternative key value

homer = User.get("homer@simpson.com",alt_key="email")
if homer:
    print(f"Name: {homer.name}, Email: {homer.email}")
else:
    print("User not found")
Name: Homer Simpson, Email: homer@simpson.com

Now let’s modify our record and save it back to our database and retreive back

homer.email = "homer.simpson@simpson.com"
homer.save()
homer = User.get("homer.simpson@simpson.com",alt_key="email")
homer.email
'homer.simpson@simpson.com'

Let’s define a bit more Simprons, this time like this

bart = User()
bart.name = "Bart Simpson"
bart.email = "bart@simpson.com"
bart.password = "password"
bart.joined_at = datetime.now()
bart.save()

bart.name, bart.email
('Bart Simpson', 'bart@simpson.com')

Let’s retrive records in our table. We can simply do that by calling all function

User.all()
[User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 1, 27, 746940), id=UUID('e1d719e2-21a4-40c1-ab9b-062e0808f101'), updated_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 870936), created_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 783496), password='password'),
 User(email='bart@simpson.com', name='Bart Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 1, 27, 909419), id=UUID('7aa9cd07-59c4-4f34-8bdd-df9b05453efb'), updated_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 914354), created_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 914332), password='password'),
 User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 2, 4, 408489), id=UUID('f4ff6c91-8fcf-44a8-9874-cf2535a8d10c'), updated_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 552857), created_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 434347), password='password'),
 User(email='bart@simpson.com', name='Bart Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 2, 4, 602805), id=UUID('455cbf7d-b8f6-407a-8ae6-f80f814d9735'), updated_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 606104), created_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 606086), password='password')]

Here we can see that we have forgot to set some unique values to our fields and prevent duplicates. So let’s remove our duplicates manualy now

First, we can use search to get all the records that contain some character in some of their string fields. This is usefull for filtering records where you’re not sure where the value shuld match.

users = User.search(search_value="Homer")
for user in users:
    print(f"Name: {user.name} , Email: {user.email}, ID: {user.id}")
Name: Homer Simpson , Email: homer.simpson@simpson.com, ID: e1d719e2-21a4-40c1-ab9b-062e0808f101
Name: Homer Simpson , Email: homer.simpson@simpson.com, ID: f4ff6c91-8fcf-44a8-9874-cf2535a8d10c

You can also set the fields you want to retreive from specific fields using fields argument. This will now not return the instance of the User rable but a list of tuples.

users = User.search(search_value="Simpson", fields=['name','email'])
users
[('Bart Simpson', 'bart@simpson.com'),
 ('Bart Simpson', 'bart@simpson.com'),
 ('Homer Simpson', 'homer.simpson@simpson.com'),
 ('Homer Simpson', 'homer.simpson@simpson.com')]

Now let’s retreive our records again

users = User.search(search_value="bart")
users
[User(email='bart@simpson.com', name='Bart Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 2, 4, 602805), id=UUID('455cbf7d-b8f6-407a-8ae6-f80f814d9735'), updated_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 606104), created_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 606086), password='password'),
 User(email='bart@simpson.com', name='Bart Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 1, 27, 909419), id=UUID('7aa9cd07-59c4-4f34-8bdd-df9b05453efb'), updated_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 914354), created_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 914332), password='password')]

..and remove the first two results using the delete function

for user in users[:len(users)-1]:
    user.delete()

for user in User.all():
    print(user.name)
Homer Simpson
Bart Simpson
Homer Simpson

we also have the option to filter the records using filter function for a specific model field.

results = User.filter(name="Homer Simpson")
results
[User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 1, 27, 746940), id=UUID('e1d719e2-21a4-40c1-ab9b-062e0808f101'), updated_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 870936), created_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 783496), password='password'),
 User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 2, 4, 408489), id=UUID('f4ff6c91-8fcf-44a8-9874-cf2535a8d10c'), updated_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 552857), created_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 434347), password='password')]
results = User.filter(email="homer.simpson@simpson.com")
results
[User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 1, 27, 746940), id=UUID('e1d719e2-21a4-40c1-ab9b-062e0808f101'), updated_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 870936), created_at=datetime.datetime(2024, 12, 19, 15, 1, 27, 783496), password='password'),
 User(email='homer.simpson@simpson.com', name='Homer Simpson', joined_at=datetime.datetime(2024, 12, 19, 16, 2, 4, 408489), id=UUID('f4ff6c91-8fcf-44a8-9874-cf2535a8d10c'), updated_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 552857), created_at=datetime.datetime(2024, 12, 19, 15, 2, 4, 434347), password='password')]

Similar to search, filter can take the same argumants, like fields, sorting_field and other (for full list navigate to the db section).

results = User.filter(name="Simp",exact_match=False,fields=["name","email"])
results
[]

We can also combine field filters.

results = User.filter(name="simp",email="hom",exact_match=False,fields=["name","email"])
results
[]

For more deatails visit related docs for SQLModel and Alembic

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastsqlmodel-0.1.2.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

FastSQLModel-0.1.2-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file fastsqlmodel-0.1.2.tar.gz.

File metadata

  • Download URL: fastsqlmodel-0.1.2.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.10.12

File hashes

Hashes for fastsqlmodel-0.1.2.tar.gz
Algorithm Hash digest
SHA256 90828f613cbfcb52adb7aa361335c529bbea83f43ebf2aef32fed022bec8a1b6
MD5 c72b05ed89bf13349d03e3bb8fd4f430
BLAKE2b-256 dad2873cca91886242af9479f4f34c8e35adf2674f131c5374a4aafdd480559a

See more details on using hashes here.

File details

Details for the file FastSQLModel-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: FastSQLModel-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.10.12

File hashes

Hashes for FastSQLModel-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 48f36d2d37499b00e8b08676a3a63bce4c12e0c44d7fc391363aff3a4d7d557c
MD5 8eae1cb32c6e118f12fdca37590d57cb
BLAKE2b-256 7bf19d480bccd086e606cb3949e6c08c5f279f9b85e885f367c1611a96ece2c8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page