A CLI tool to generate full-stack web projects from SQLModel
Project description
OneSite
OneSite is a model-driven CLI tool that generates full-stack web applications (FastAPI + React/Vite) from SQLModel definitions.
pip install onesite
Quick Start
# Create a new project
site create myproject
cd myproject
# Define your SQLModel classes in models/
# Then sync to generate backend and frontend code
site sync --install
# Run both servers
site run
- Backend: http://localhost:8000 (Docs: http://localhost:8000/docs)
- Frontend: http://localhost:5173
- Default admin:
admin@example.com/admin
Defining Models
Basic Model
from typing import Optional
from sqlmodel import Field, SQLModel
class Product(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
price: float
is_active: bool = True
Foreign Key
class Post(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
title: str
content: str
user_id: Optional[int] = Field(default=None, foreign_key="user.id")
FK fields auto-detect their target table. List pages display the related record's label (first unique + is_search_field field) instead of raw IDs.
Many-to-Many
class PostTagLink(SQLModel, table=True):
__onesite__ = {"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)
M2M link tables generate multi-select components on the source model's form. If a link table has extra non-FK fields, it generates standalone CRUD pages for editing them.
User-Owned Resources (owner_field)
Mark a model as user-owned so non-admin users can only see/edit their own records:
class Item(SQLModel, table=True):
__onesite__ = {
"owner_field": "owner_id",
}
id: Optional[int] = Field(default=None, primary_key=True)
name: str
owner_id: Optional[int] = Field(default=None, foreign_key="user.id")
- Users only see their own items (list filtered by
owner_id = current_user.id) - Admins/developers see all items
- Create forces
owner_id = current_user.idfor non-admin users - Detail/update/delete return 404 if the item doesn't belong to the current user
- Frontend shows "My Items" in the menu and page title for user role
Permission System
Three-layer permission system: model-level CRUD, field-level CRU, and frontend visibility.
Permission chars: c = create, r = read, u = update, d = delete.
Permission Formats
Both model-level and field-level permissions accept two formats:
- Dict format — specify per-role permissions individually
- String format — shorthand that applies the same permission chars to all roles
# Dict format (per-role)
"permissions": {"user": "ru", "admin": "rcud", "developer": "rcud"}
# String format (applies to all roles, equivalent to above)
"permissions": "rcud"
"r" is equivalent to {"user": "r", "admin": "r", "developer": "r"}. Use string format when all roles have the same permission level, dict format when you need per-role differentiation.
Layer 1 — Model-level CRUD
class Product(SQLModel, table=True):
__onesite__ = {
# Dict format — per-role
"permissions": {
"user": "ru", # read + update
"admin": "rcud", # full access
"developer": "rcud",
},
# String format — all roles get same perms (equivalent)
# "permissions": "rcud",
"visible": ["admin", "developer"], # menu visibility
}
Role hierarchy: developer >= admin >= user. Missing roles default to "" (no access). If unset, all roles get "crud".
Layer 2 — Field-level CRU
Controls field inclusion in schemas and forms. d is model-level only, automatically stripped at field level.
email: str = Field(sa_column_kwargs={"info": {"site_props": {
# Dict format — per-role
"permissions": {
"user": "r",
"admin": "rcu",
"developer": "rcu",
}
# String format — all roles get same perms (equivalent)
# "permissions": "rcu",
}}})
Special field defaults: id = read-only, created_at = read-only, updated_at = read+update.
Key Features
- Code generation: Backend (FastAPI, SQLModel, Pydantic) + Frontend (React, Tailwind, Zustand)
- CRUD with validation: Auto-generated endpoints and forms with unique constraint checks
- Search & filters: Mark fields with
is_search_fieldto generate filter panels - Smart FK display: Shows related record labels instead of raw IDs
- File & image upload: Auto-detected by field name conventions (
_image,_file,avatar, etc.) - JSON fields: Support for
Dict,List, and Pydantic models as JSON columns with structured editors - CSV import/export: Configure
importable/exportableon any model - Notifications: Optional notification center with WebSocket real-time push
- Dashboard: Auto-generated stats cards and charts (bar, line, pie)
- Scheduled tasks: Cron and interval tasks via APScheduler, manageable from the UI
- Internationalization: EN/ZH locale files generated from model translations
- Themes: Built-in styles (normal, industrial, anime, cute)
- Containerization: Docker/Podman build and Compose support
- Authentication: JWT-based login, role-based access control
- Singleton models: Config-style models (e.g.,
SystemConfig) with singleton endpoints - Custom actions: One-click buttons with conditional logic and field updates
- Auto refresh: Real-time data monitoring with configurable intervals
Site Configuration
Customize via site_config.json in the project root:
{
"project_name": "My Project",
"style": "anime",
"radius": 1.0,
"database_url": "sqlite:///./app.db",
"nav_order": ["user", "product", "tag"]
}
Styles: normal, industrial, anime, cute — full color systems, typography, and shadows.
Project Structure
myproject/
├── site_config.json # Project configuration
├── models/ # SQLModel definitions (source of truth)
├── backend/
│ ├── app/
│ │ ├── api/endpoints/ # Generated REST endpoints
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/ # Business logic
│ │ ├── cruds/ # CRUD operations
│ │ ├── models/ # Synced SQLModel classes
│ │ ├── core/ # Config, security, database
│ │ └── initial_data.py # Admin user seeding
│ └── tests/
└── frontend/
└── src/
├── pages/ # Generated list/detail pages
├── services/ # API clients
├── stores/ # Zustand state
└── components/ # UI components
Commands
| Command | Description |
|---|---|
site init |
Initialize config and base models in existing project |
site create <name> |
Create new project scaffold |
site sync [--install] |
Sync models and generate code |
site run [backend|frontend|all] |
Start development servers |
site build [--engine] [--tag] [--port] |
Build Docker/Podman images |
site compose up|down|logs -f |
Run docker-compose commands |
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.15.tar.gz.
File metadata
- Download URL: onesite-0.1.15.tar.gz
- Upload date:
- Size: 99.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
423094d1c79b718c3210855614be05e7abc3b5039b6fabcf6a41c400550b784f
|
|
| MD5 |
dde1468b1650ef5b984a5da3ac60aec7
|
|
| BLAKE2b-256 |
5f161b2b285d46e287e9db9842877206d533e1cbc6c5ba85a41a310ac8fff40b
|
File details
Details for the file onesite-0.1.15-py3-none-any.whl.
File metadata
- Download URL: onesite-0.1.15-py3-none-any.whl
- Upload date:
- Size: 272.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 |
d4ae439add33955c306795a2382d4faae894b5d35a78b0809449b9f3aefd99a8
|
|
| MD5 |
f5332cb8f5c56299156b6b10bf33f4fb
|
|
| BLAKE2b-256 |
845e348a8b6c9a9abbefea082a92e20e8b10483fc5d4a98d900d1aceffa6f007
|