Generate type-safe Pydantic models that simplify working with supabase-py
Project description
supabase-models
Generate type-safe Pydantic models from your Supabase database schema ready to use with supabase-py.
Key features
- Schema introspection: Automatically extracts table structures, constraints, and relationships
- Type-safe models: Creates Pydantic models with type hints and validation
- JSON serialization: Generated models include
dump()andload()methods for sending/receiving data via supabase-py - Constraint validation: Translates database column constraints to Pydantic validators
- Customizable output: Uses a built-in template by default, or modify the Jinja2 template to match your needs
Prerequisites
This package is designed to work with:
- supabase-py - the recommended Supabase Python client
- PostgreSQL databases (including Supabase projects)
Installation
pip install supabase-models
# or with uv (recommended)
uv add supabase-models
Basic Usage
1. Generate Models
supabase-models --database-url postgresql://user:password@localhost:5432/database
Default behavior:
- Output file:
models.pyin current directory - Schema:
public - Template: Built-in Jinja2 template
[!TIP] See CLI Reference below for all available options and configuration methods
2. Use with supabase-py
The generated models provide dump() and load() methods to simplify working with supabase-py:
dump()- Use when sending data to Supabaseload()- Use when loading received data from Supabase responses
from supabase import create_client, Client
from models import Product, ProductStatusEnum # Noqa # Your generated models
# Initialize Supabase client
supabase_client: Client = ... # Noqa
# INSERT: Create and insert a new product
product = Product(name="Wireless Mouse", sku="WM-2024", price=29.99, status=ProductStatusEnum.DRAFT)
insert_response = supabase_client.table(Product.table_name).insert(product.dump()).execute()
# SELECT: Query and parse products back to typed models
select_response = supabase_client.table(Product.table_name).select("*").execute()
products: list[Product] = Product.load(select_response)
See the section below for details on how these models are generated.
Generated Output
Given this database schema:
-- Create enum types
CREATE TYPE product_status AS ENUM ('draft', 'active', 'archived');
-- Create tables
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
sku VARCHAR(20) UNIQUE NOT NULL CHECK (sku ~ '^[A-Z]{2,3}-[0-9]{3,4}$'),
price DECIMAL(10,2) CHECK (price > 1),
category_id BIGINT REFERENCES categories(id),
status product_status DEFAULT 'draft',
created_at TIMESTAMPTZ DEFAULT NOW()
);
The tool generates the following models:
Note: Simplified example showing key capabilities. Some code sections abbreviated for clarity.
from datetime import datetime
from decimal import Decimal
from enum import Enum
from typing import Any, ClassVar
from pydantic import BaseModel, Field
class ProductStatusEnum(str, Enum):
"""Enum for product_status values."""
DRAFT = "draft"
ACTIVE = "active"
ARCHIVED = "archived"
class SupabaseBaseModel(BaseModel):
"""Base model with supabase-py integration helpers."""
...
# All helper logic is automatically generated
# Main methods: load() for parsing responses, dump() for preparing data
# Additional utilities for validation and type conversion are included
class Product(SupabaseBaseModel):
"""Model for 'products' table.
Attributes:
id (int | None): Primary key column; Auto-increment.
name (str | None): Required column.
sku (str | None): Required column; Unique.
price (Decimal | float | None): Optional column.
category_id (int | None): Optional column; Foreign key to 'categories'.
status (ProductStatusEnum | None): Optional column; Default: 'draft'.
created_at (datetime | None): Optional column; Default: now().
categories (Category | None): Related table Category (requires categories(*) in query)
"""
table_name: ClassVar[str] = "products"
_required_columns: ClassVar[list[str]] = ["name", "sku"]
# Primary key columns:
id: int | None = Field(default=None, description="Auto-increment")
# Required columns:
name: str | None = Field(default=None, max_length=100)
sku: str | None = Field(default=None, description="Unique", max_length=20, pattern=r"^[A-Z]{2,3}-[0-9]{3,4}$")
# Optional columns:
price: Decimal | float | None = Field(default=None, gt=1)
category_id: int | None = Field(default=None, description="Foreign key to 'categories'")
status: ProductStatusEnum | None = Field(default=None, description="Default: 'draft'")
created_at: datetime | None = Field(default=None, description="Default: now()")
# Relations:
categories: "Category | None" = Field(default=None, description="Related table Category. Include categories(*) in query to populate.")
class Category(SupabaseBaseModel):
"""Model for 'categories' table.
Attributes:
id (int | None): Primary key column; Auto-increment; Default: nextval('categories_id_seq').
name (str | None): Required column.
"""
table_name: ClassVar[str] = "categories"
_required_columns: ClassVar[list[str]] = ["name"]
# Primary key columns:
id: int | None = Field(default=None, description="Auto-increment; Default: nextval('categories_id_seq')")
# Required columns:
name: str | None = Field(default=None, max_length=100)
Supported Features
| PostgreSQL Feature | Pydantic Output |
|---|---|
| Basic Features | |
PRIMARY KEY |
Field descriptions |
FOREIGN KEY |
Relationship information |
NOT NULL |
Required field detection |
DEFAULT value |
Field descriptions |
UNIQUE |
Field descriptions |
AUTOINCREMENT |
Field descriptions |
| Data Types | |
VARCHAR(n), CHAR(n), TEXT |
str with Field(max_length=n) |
INTEGER, BIGINT, SMALLINT |
int |
DECIMAL(p,s), NUMERIC(p,s) |
Decimal | float with precision bounds |
REAL, DOUBLE PRECISION |
float |
BOOLEAN |
bool |
DATE, TIMESTAMP, TIMESTAMPTZ |
datetime |
TIME, TIMETZ |
time | str (for timezone types) |
JSON, JSONB |
dict[str, Any] |
UUID |
UUID |
BYTEA |
bytes |
SERIAL, BIGSERIAL |
int with auto-increment |
ENUM types |
CustomEnum(str, Enum) |
| Constraints | |
VARCHAR(n) |
Field(max_length=n) |
CHECK (x > 0) |
Field(gt=0) |
CHECK (x >= 10) |
Field(ge=10) |
CHECK (x <= 1000) |
Field(le=1000) |
CHECK (x < 100) |
Field(lt=100) |
CHECK (x BETWEEN 0 AND 1000) |
Field(ge=0, le=1000) |
CHECK (char_length(x) >= 5) |
Field(min_length=5) |
CHECK (char_length(x) <= 50) |
Field(max_length=50) |
CHECK (x ~ '^.+@.+$') |
Field(pattern=r"^.+@.+$") |
CHECK (x ~* '^.+@.+$') |
Field(pattern=r"^.+@.+$") |
[!NOTE]
Constraint parsing is continuously improving. Please open an issue with examples of constraints you'd like to see supported!
CLI Reference
supabase-models [OPTIONS]
Options:
--database-url TEXT PostgreSQL connection string
-o, --output TEXT Output file (default: models.py)
-s, --schema TEXT Database schema (default: public)
-t, --template TEXT Custom Jinja2 template file
-v, --verbose Enable verbose logging
--version Show version
--help Show help
CLI Examples
# Basic usage with environment variable
export DATABASE_URL="postgresql://user:pass@host:port/db"
supabase-models
# Direct database URL
supabase-models --database-url "postgresql://user:pass@host:port/db"
# Custom output and schema
supabase-models --output app/models.py --schema public --verbose
# Multiple schemas
supabase-models --schema auth --output auth_models.py
supabase-models --schema public --output public_models.py
Development
# Install development dependencies
uv sync
# Format and lint
uv run ruff format .
uv run ruff check .
# Run tests
uv run pytest
Contributing
For issues and contributions, visit the GitHub repository.
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 supabase_models-0.0.2.dev1.tar.gz.
File metadata
- Download URL: supabase_models-0.0.2.dev1.tar.gz
- Upload date:
- Size: 70.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
181eb4311761aaa2581d8e032f71845e3b204b3ef32e1edfcc4553f80ed47a67
|
|
| MD5 |
c1db84087345afd7add049b8abe9afeb
|
|
| BLAKE2b-256 |
d4de230136b4e7f2fe2c00dd53425ebf6591130f68d383c7c216972007ca6b4a
|
Provenance
The following attestation bundles were made for supabase_models-0.0.2.dev1.tar.gz:
Publisher:
publish-to-pypi.yml on martin-foka/supabase-models
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
supabase_models-0.0.2.dev1.tar.gz -
Subject digest:
181eb4311761aaa2581d8e032f71845e3b204b3ef32e1edfcc4553f80ed47a67 - Sigstore transparency entry: 521317159
- Sigstore integration time:
-
Permalink:
martin-foka/supabase-models@804f1d836e733d68c0256b5328fa0b902d88014b -
Branch / Tag:
refs/tags/0.0.2.dev1 - Owner: https://github.com/martin-foka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@804f1d836e733d68c0256b5328fa0b902d88014b -
Trigger Event:
release
-
Statement type:
File details
Details for the file supabase_models-0.0.2.dev1-py3-none-any.whl.
File metadata
- Download URL: supabase_models-0.0.2.dev1-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e41fc7cea1c2df1431b7eb41c4b29842c0df1a735bd343c98ee1465408dba5a3
|
|
| MD5 |
d219049bb571e390c663c0c2838dc466
|
|
| BLAKE2b-256 |
6d0dca37e7c657f59a8c513c89d1b22a35b7508d13a39d0a019eb52212338356
|
Provenance
The following attestation bundles were made for supabase_models-0.0.2.dev1-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on martin-foka/supabase-models
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
supabase_models-0.0.2.dev1-py3-none-any.whl -
Subject digest:
e41fc7cea1c2df1431b7eb41c4b29842c0df1a735bd343c98ee1465408dba5a3 - Sigstore transparency entry: 521317188
- Sigstore integration time:
-
Permalink:
martin-foka/supabase-models@804f1d836e733d68c0256b5328fa0b902d88014b -
Branch / Tag:
refs/tags/0.0.2.dev1 - Owner: https://github.com/martin-foka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@804f1d836e733d68c0256b5328fa0b902d88014b -
Trigger Event:
release
-
Statement type: