Skip to content

Instantly share code, notes, and snippets.

@bpeterso2000
Created May 9, 2025 20:37
Show Gist options
  • Save bpeterso2000/2ef45b8192f2e5eac07961e7d75ef951 to your computer and use it in GitHub Desktop.
Save bpeterso2000/2ef45b8192f2e5eac07961e7d75ef951 to your computer and use it in GitHub Desktop.
from fasthtml.common import *
from fastlite import Database, Model, Field
from dataclasses import dataclass, fields
from typing import Optional
import sqlite3
# Initialize FastHTML app with Tailwind CSS for styling
app = FastHTML(hdrs=(picolink, Script(src="https://cdn.tailwindcss.com")))
# Initialize FastLite database
db = Database("example.db")
# Example dataclass model for a "User" table
@dataclass
class User(Model):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field()
email: str = Field()
# Create the table if it doesn't exist
db.create(User)
# DataGrid component
def DataGrid(model, db_table):
# Get field names from the dataclass (excluding primary key for form)
model_fields = [f.name for f in fields(model) if f.name != 'id']
# Add button with UXWing add icon
add_btn = A(
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/checkmark-cross/add-icon.svg",
cls="w-6 h-6 inline-block", alt="Add"),
" Add New",
href=f"/add/{model.__name__.lower()}",
cls="inline-flex items-center px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
)
# Table headers
headers = [Th(f.name.capitalize()) for f in fields(model)] + [Th("Actions")]
# Table rows
rows = []
for record in db_table.all():
row_cells = [Td(getattr(record, f)) for f in model_fields]
row_cells.append(Td(getattr(record, 'id'))) # Include ID for reference
# Edit and Delete buttons with UXWing icons
actions = Td(
A(
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/editing-modification/edit-icon.svg",
cls="w-5 h-5 inline-block", alt="Edit"),
href=f"/edit/{model.__name__.lower()}/{record.id}",
cls="text-blue-500 hover:text-blue-700 mr-2"
),
A(
Img(src="https://uxwing.com/wp-content/themes/uxwing/download/checkmark-cross/delete-icon.svg",
cls="w-5 h-5 inline-block", alt="Delete"),
href=f"/delete/{model.__name__.lower()}/{record.id}",
cls="text-red-500 hover:text-red-700",
hx_delete=f"/delete/{model.__name__.lower()}/{record.id}",
hx_confirm="Are you sure you want to delete this record?",
hx_target="closest tr",
hx_swap="outerHTML"
)
)
rows.append(Tr(*row_cells, actions))
# Return the complete table with add button
return Div(
add_btn,
Table(
Thead(*headers),
Tbody(*rows),
cls="min-w-full divide-y divide-gray-200 mt-4"
),
cls="p-4"
)
# Form component for Add/Edit
def ModelForm(model, record=None):
model_fields = [f.name for f in fields(model) if f.name != 'id']
inputs = [
Div(
Label(f.name.capitalize(), fr=f.name, cls="block text-sm font-medium text-gray-700"),
Input(name=f.name, value=getattr(record, f.name, ""),
cls="mt-1 block w-full border-gray-300 rounded-md shadow-sm")
) for f in model_fields
]
return Form(
*inputs,
Button("Save", type="submit", cls="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"),
method="post",
action=f"/save/{model.__name__.lower()}/{getattr(record, 'id', '')}",
cls="space-y-4 max-w-md",
hx_post=f"/save/{model.__name__.lower()}/{getattr(record, 'id', '')}",
hx_target="#content",
hx_swap="innerHTML"
)
# Routes
@app.get("/")
def home():
return Div(
H1("User Management", cls="text-2xl font-bold mb-4"),
DataGrid(User, db.t.users),
id="content",
cls="container mx-auto p-4"
)
@app.get("/add/{model_name}")
def add_form(model_name: str):
model = globals()[model_name.capitalize()]
return Div(
H2("Add New Record", cls="text-xl font-bold mb-4"),
ModelForm(model),
A("Back", href="/", cls="mt-4 inline-block text-blue-500 hover:underline"),
id="content",
cls="container mx-auto p-4"
)
@app.get("/edit/{model_name}/{id}")
def edit_form(model_name: str, id: int):
model = globals()[model_name.capitalize()]
record = db.t[model_name].get(id)
return Div(
H2("Edit Record", cls="text-xl font-bold mb-4"),
ModelForm(model, record),
A("Back", href="/", cls="mt-4 inline-block text-blue-500 hover:underline"),
id="content",
cls="container mx-auto p-4"
)
@app.post("/save/{model_name}/{id}")
def save(model_name: str, id: Optional[int], **kwargs):
model = globals()[model_name.capitalize()]
table = db.t[model_name]
if id:
table.update(kwargs, id=id)
else:
table.insert(kwargs)
return DataGrid(model, table)
@app.delete("/delete/{model_name}/{id}")
def delete(model_name: str, id: int):
table = db.t[model_name]
table.delete(id)
return ""
# Run the app
if __name__ == "__main__":
serve()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment