A CLI tool to generate full-stack web projects from SQLModel
Project description
OneSite
OneSite is a powerful model-driven CLI tool that automatically generates a full-stack web application (FastAPI + React/Vite) from simple Python SQLModel definitions.
It automates the repetitive work of building CRUD APIs, database schemas, and frontend management pages, allowing you to focus on business logic.
Features
- Full-Stack Generation: Generates Backend (FastAPI, SQLModel, Pydantic) and Frontend (React, Tailwind, Zustand, Lucide Icons).
- Model-Driven: Define your data models in standard Python code, and let OneSite handle the rest.
- Auto CRUD & Validation: Automatically generates Create, Read, Update, Delete APIs and UI, including unique constraints validation.
- Smart UI Components:
bool-> Switch / BadgeEnum-> Select / Badgedatetime-> Text- Image Upload: Detects image fields (e.g.
avatar,_image) and generates file upload and preview components. - File Attachment: Detects file fields (e.g.
report_file,_filesuffix) and generates file upload components with built-in preview.- Preview Support: PDF, Word (docx), Excel (xlsx, csv), Markdown, Code/Text, Video, Audio, Images.
- Foreign Key: Auto-detects foreign keys and generates searchable select dropdowns (
SearchableSelect). - Many-to-Many: Supports M2M relationships via link tables, generating multi-select components.
- One-to-Many (Reverse FK): Displays related items in a paginated list on the detail page (e.g. Products under a Category). Configurable.
- Pagination: Built-in standard pagination support for all list views.
- Auto Refresh: Configurable auto-refresh for real-time data monitoring.
- Authentication & Security:
- Built-in Login: Modern login page with JWT authentication.
- Protected Routes: Automatic auth guards for frontend pages.
- Secure APIs: CRUD endpoints default to authenticated access; static files are public.
- User Management: Secure password hashing and role-based field access.
- Containerization: Built-in support for Docker/Podman build and Compose.
Installation
# Clone the repository
git clone https://github.com/IronSpiderMan/OneSite.git
cd OneSite
# Install the tool in editable mode
pip install -e .
Quick Start
1. Create a New Project
site create myproject
cd myproject
This creates a new directory structure:
myproject/
├── backend/ # FastAPI Backend
├── frontend/ # React Frontend
└── models/ # Your Data Models (Source of Truth)
2. Define Your Models
Add your models to the models/ directory.
Basic Model
models/product.py:
from typing import Optional
from sqlmodel import Field, SQLModel
from enum import Enum
class Category(str, Enum):
ELECTRONICS = "electronics"
CLOTHING = "clothing"
class Product(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
price: float
is_active: bool = True
category: Category = Category.ELECTRONICS
# Image field (auto-detected by name 'image', 'avatar', or '_image' suffix)
image: Optional[str] = Field(default=None, sa_column_kwargs={"info": {"site_props": {"component": "image"}}})
File Attachments
models/document.py:
from typing import Optional
from sqlmodel import Field, SQLModel
class Document(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
title: str
# Method 1: Auto-detection via '_file' suffix
report_file: Optional[str] = Field(default=None)
# Method 2: Explicit component definition
attachment: Optional[str] = Field(default=None, sa_column_kwargs={"info": {"site_props": {"component": "file"}}})
# Method 3: Disable download (preview only)
preview_only: Optional[str] = Field(default=None, sa_column_kwargs={"info": {"site_props": {"component": "file", "allow_download": False}}})
Foreign Key Relationship
models/post.py:
from typing import Optional
from sqlmodel import Field, SQLModel
class Post(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
title: str
content: str
# Foreign Key to User
# Configure reverse display on the field itself
# reverse_display: Controls whether this relationship is shown on the target model's detail page (e.g. User page)
# Default is True.
user_id: Optional[int] = Field(default=None, foreign_key="user.id", sa_column_kwargs={"info": {"site_props": {"reverse_display": True}}})
Many-to-Many Relationship
To define a Many-to-Many relationship (e.g., Posts have many Tags), create a link table model with specific metadata.
models/tag.py:
from typing import Optional
from sqlmodel import Field, SQLModel
class Tag(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(unique=True)
models/post_tag_link.py:
from typing import Optional
from sqlmodel import Field, SQLModel
class PostTagLink(SQLModel, table=True):
# Required metadata to identify this as a M2M link table
__table_args__ = {"info": {"site_props": {"is_link_table": True}}}
post_id: Optional[int] = Field(default=None, foreign_key="post.id", primary_key=True)
tag_id: Optional[int] = Field(default=None, foreign_key="tag.id", primary_key=True)
OneSite will automatically inject a tag_ids field into the Post form, allowing you to select multiple Tags.
3. Advanced Configuration
You can customize field behavior using site_props in sa_column_kwargs or schema_extra.
Note: when you use sa_column=Column(...) in SQLModel, you cannot also pass sa_column_kwargs (SQLModel limitation). In that case, put site_props in schema_extra instead.
Field Permissions & Validation
Control field visibility and validation requirements for Create/Update operations.
class User(SQLModel, table=True):
# ...
email: str = Field(unique=True) # Unique constraint validation
password: str = Field(sa_column_kwargs={"info": {"site_props": {
"permissions": "cu", # 'c'=Create, 'u'=Update. 'r'=Read (omitted here, so password is never sent to frontend)
"create_optional": False, # Required when creating a user
"update_optional": True # Optional when updating (leave blank to keep current password)
}}})
unique=True: Adds a unique constraint to the field. OneSite automatically generates validation logic in Create/Update APIs to prevent duplicate entries (returns400 Bad Request).permissions: String withr(read),c(create),u(update). Default isrcu.create_optional: IfTrue, field is not required in Create form.update_optional: IfTrue, field is not required in Update form.
JSON Fields (Object & Array)
OneSite supports two JSON field kinds:
- Object JSON:
Dict[str, Any](ordict) - Array JSON:
List[Any](orlist)
JSON Fields (BaseModel)
If you define a Pydantic model in advance, you can use it directly as a JSON field type. OneSite will render a structured UI form for it, and you can switch between UI mode and JSON mode.
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel
from sqlalchemy import Column
from sqlalchemy.types import JSON
from sqlmodel import Field, SQLModel
class Gender(str, Enum):
male = "male"
female = "female"
class Test(BaseModel):
name: str
gender: Gender
is_teacher: bool
class NestedJsonDemo(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
t: Test = Field(sa_column=Column(JSON))
ts: List[Test] = Field(default_factory=list, sa_column=Column(JSON))
t: Test: Renders fields likename,gender,is_teacheras normal inputs/selects/switch.ts: List[Test]: Supports adding/removing multiple items, each item has the same UI form.- You can always switch to JSON mode to paste/edit raw JSON directly.
Recommended model definition (works across DBs that support JSON):
from typing import Any, Dict, List, Optional
from sqlalchemy import Column
from sqlalchemy.types import JSON
from sqlmodel import Field, SQLModel
class JsonDemo(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
meta: Dict[str, Any] = Field(
default_factory=dict,
sa_column=Column(JSON),
schema_extra={"site_props": {"component": "json", "json_kind": "object"}},
)
tags: List[Any] = Field(
default_factory=list,
sa_column=Column(JSON),
schema_extra={"site_props": {"component": "json", "json_kind": "array"}},
)
- If you omit
component/json_kind, OneSite will still infer JSON UI fromDict[...]/List[...]types. - The generated UI provides a JSON editor (formatting on blur + basic validation).
Auto Refresh
Enable automatic data refreshing for list and detail views. This is useful for monitoring dashboards or real-time data.
class DashboardMetric(SQLModel, table=True):
# Enable auto-refresh every 5 seconds (5000ms)
__table_args__ = {"info": {"site_props": {
"auto_refresh": True,
"refresh_interval": 5000
}}}
id: Optional[int] = Field(default=None, primary_key=True)
name: str
value: float
auto_refresh:bool. IfTrue, adds an "Auto Refresh" toggle to the UI.refresh_interval:int(milliseconds). The default refresh interval (default: 5000ms). Users can change this in the UI.
Site Configuration (site_config.json)
You can customize the look and feel of your application by editing site_config.json in the project root.
{
"project_name": "My Awesome Project",
"style": "anime",
"radius": 1.0,
"database_url": "sqlite:///./app.db"
}
- style: Presets for complete UI style. Each style includes full light/dark color system, border/input tone, font family, heading weight, card shadow, and page background texture.
normal: Professional SaaS style, clean white/blue system, balanced spacing and neutral shadow.industrial: Mechanical dashboard style, colder grayscale palette, sharp corners, stronger borders and grid texture.anime: High-saturation fantasy style, vibrant violet/cyan/yellow accents, large round corners and colorful glow shadows.cute: Soft pastel style, warm pink/cream palette, extra round corners, gentle shadows and playful gradient texture.- Legacy aliases are still accepted for backward compatibility:
slate,blue,red,green,orange,purple,yellow.
- radius: Optional global border radius override. If omitted, each style uses its own default radius.
4. Sync and Generate Code
Run the sync command to generate backend and frontend code based on your models. Use --install flag for the first run to install dependencies.
site sync --install
5. Run the Application (Local Development)
Start both backend and frontend servers with one command:
site run
- Backend: http://localhost:8000 (Docs: http://localhost:8000/docs)
- Frontend: http://localhost:5173
Default Admin Credentials:
- Email:
admin@example.com - Password:
admin
6. Containerization & Deployment
OneSite makes it easy to build and run your application using Docker/Podman.
Build Images & Generate Configuration
This command builds the container images and generates a docker-compose.yml configured to use them.
# Build with default settings (Docker, tag: latest, port: 3000)
site build
# Or customize settings
site build --engine podman --tag v1.0 --port 8080
Run with Compose
Start the services using the generated configuration.
site compose up -d
- Frontend: http://localhost:3000 (or your custom port)
- Backend: http://localhost:8000 (internal to compose network)
Project Structure
myproject/
├── models/ # Define your SQLModel classes here
├── backend/
│ ├── app/
│ │ ├── api/ # Generated API endpoints
│ │ ├── cruds/ # Generated CRUD logic
│ │ ├── models/ # Synced models
│ │ ├── schemas/ # Generated Pydantic schemas
│ │ ├── services/ # Business logic
│ │ ├── core/ # Config, Security, DB
│ │ │ └── security.py # Password hashing & Auth
│ │ └── initial_data.py # Data seeding (Admin user)
│ ├── uploads/ # User uploaded files
│ └── ...
└── frontend/
├── src/
├── components/ # UI Components (Button, Input, Modal, ImageUpload, etc.)
├── pages/ # Generated List/Edit Pages
├── services/ # Generated API Clients
├── stores/ # Generated State Management
└── ...
Commands Reference
site create <name>: Create a new project scaffold.site sync [--install/-i]: Sync models and generate code. Use-ito install Python and Node dependencies.site run [component]: Run the project locally.componentcan bebackend,frontend, orall(default).site build [--component/-c] [--engine/-e] [--tag/-t] [--port/-p]: Build container images and generatedocker-compose.yml.--component:backend,frontend, orall(default).--engine:docker(default) orpodman.--tag: Image tag (default:latest).--port: Frontend exposed port (default:3000).
site compose <command> [args]...: Run docker-compose commands using the generated file.- Examples:
site compose up -d,site compose down,site compose logs -f.
- Examples:
Requirements
- Python 3.10+
- Node.js & npm (for frontend)
- Docker or Podman (optional, for containerization)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file onesite-0.1.7.tar.gz.
File metadata
- Download URL: onesite-0.1.7.tar.gz
- Upload date:
- Size: 21.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d3300b5410a82d183255e507f35c358f98b01ddff0f013cffa7f6ac46cc69fa
|
|
| MD5 |
fdf345ed1a339d3e0269259641d0e1e1
|
|
| BLAKE2b-256 |
2c366f94096fc1dc6e9ec542820923dde198f437e0ed014c44e1734c6382c7d2
|
File details
Details for the file onesite-0.1.7-py3-none-any.whl.
File metadata
- Download URL: onesite-0.1.7-py3-none-any.whl
- Upload date:
- Size: 96.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
71bc498ec1e9660e18b77ceed14975b2c51cf3ce125bf5f076204ef477c260bd
|
|
| MD5 |
8fa70ad7907c931f278c4f2ea5abcca7
|
|
| BLAKE2b-256 |
636a421bcb7b63660789a9c8b1fbc7cd285ba315cec91e20e614d73f47143450
|