๐ ModelAPI โ A Friendly Guide to a Lightweight SQLite ORM๏
Note: ModelAPI uses a different structure than TableAPI! So if youโre coming from that, treat this as a fresh start.
๐ Table of Contents๏
๐ง Introduction๏
ModelAPI gives you a Laravel-style, class-based ORM interface for SQLite in Python. Itโs minimal, fast, and easy to use.
Think of it like this:
You define your data with Python classes.
The ORM handles schema definition, inserts, reads, updates, and deletes.
Itโs flexible enough for small scripts and powerful enough for CLI tools.
๐ Getting Started๏
Letโs walk through setting things up step-by-step!
1. Bootstrapping the Database๏
Create a file like db.py to initialize your SQLite database.
# db.py
from luminadb import Database
db = Database(":memory:") # or use "your_file.db" to persist data
This creates a simple in-memory SQLite database. For persistent storage, pass a filename instead of ":memory:".
2. Creating a Model๏
Each model is a Python class with typed fields and a schema definition.
# model/notes.py
from uuid import uuid4
from luminadb import model, BaseModel, Primary
from ..db import db
@model(db)
class Notes(BaseModel):
__schema__ = (Primary('id'),)
__auto_id__ = lambda: str(uuid4())
id: str
title: str
content: str
๐ก How it works๏
@model(db)binds the class to the database.__schema__defines your table schema. You can usePrimary(),Unique(),Foreign(), etc.__auto_id__is optional. It helps generate IDs automatically (e.g. UUIDs).
3. Running CRUD Operations๏
CREATE๏
Notes.create(title="Hello", content="World!")
You can gather user input too:
title = input('Title: ')
content = input('Content: ')
Notes.create(title=title, content=content)
READ๏
You can fetch all rows, one row, or use filters:
Notes.all() # Returns a list of all notes
Notes.first(id="123") # Returns the first match or None
Notes.one(id="123") # Returns exactly one result, else throws error
Advanced .where() filtering๏
# Find a note by title
note = Notes.where(title="Shopping List").fetch_one()
# Limit or offset
Notes.where().limit(5).fetch() # Get top 5 notes
Notes.where().offset(5).fetch() # Skip 5 and get the rest
# Count matching rows
count = Notes.where().count()
UPDATE๏
Updating a row is super simple. Fetch it first, then call .update():
note = Notes.first(id="some-id")
note.update(title="Updated", content="Updated content here.")
DELETE๏
Delete just like youโd update:
note = Notes.first(id="some-id")
note.delete()
๐ฎ Example App โ CRUD in Action๏
Hereโs a small CLI app to tie it all together:
from enum import IntEnum
from uuid import uuid4
from luminadb import Database, model, BaseModel, Primary, SKIP
db = Database(":memory:")
@model(db)
class Notes(BaseModel):
__schema__ = (Primary('id'),)
__auto_id__ = lambda: str(uuid4())
id: str
title: str
content: str
def display():
print('-'*3)
for note in Notes.all():
print(f"ID : {note.id}")
print(f"Title : {note.title}")
print(f"Content : {note.content}")
print("-"*3)
def read(prompt: str):
try:
return input(prompt)
except KeyboardInterrupt:
return SKIP
def create():
title = input("Title: ")
content = input("Content: ")
Notes.create(title=title, content=content)
def update():
note_id = input('ID: ')
note = Notes.first(id=note_id)
if note:
title = read("New title: ")
content = read("New content: ")
note.update(title=title, content=content)
else:
print("Note not found.")
def delete():
note_id = input('ID: ')
note = Notes.first(id=note_id)
if note:
note.delete()
else:
print("Note not found.")
class CMD(IntEnum):
DISPLAY = 1
CREATE = 2
UPDATE = 3
DELETE = 4
EXIT = 5
def main():
while True:
print('-'*8)
print('1. Display all notes')
print('2. Create a note')
print('3. Update a note')
print('4. Delete a note')
print('5. Exit')
try:
cmd = int(input("Command: "))
if cmd == CMD.DISPLAY:
display()
elif cmd == CMD.CREATE:
create()
elif cmd == CMD.UPDATE:
update()
elif cmd == CMD.DELETE:
delete()
elif cmd == CMD.EXIT:
break
except KeyboardInterrupt:
break
except Exception as exc:
print(f"{type(exc).__name__}: {exc}")
if __name__ == "__main__":
main()
๐ FAQ๏
Q: Can I define relationships between models?
A: Yes, using Foreign() in __schema__. This doc will be updated with examples soon.
Q: Does it support migrations? A: Not directly. The schema is defined per-model, so migrations require manual changes.
Q: How are models stored? A: The models reflect SQLite tables. Everything is automatically synced on class definition.
๐ก Tips & Notes๏
You can use any primitive Python types (e.g.
int,str,float) in your model class.Keep
__auto_id__short and efficient โ UUIDs are recommended.Donโt forget to call
Database()only once and reuse the instance.