SQL to SQLAlchemy Model

Generate a SQLAlchemy declarative model from a SQL CREATE TABLE statement.

SQL DDL Input
SQLAlchemy Model Output
SQLAlchemy Model output appears here

Related Tools

Documentation

What is SQL to SQLAlchemy?

SQL to SQLAlchemy turns CREATE TABLE statements into classic SQLAlchemy declarative models — a class(Base) per table with __tablename__ and Column(...) attributes, the declarative_base() style used across most existing SQLAlchemy 1.x projects.

How it works

Each SQL type maps to a SQLAlchemy column type — INTEGER/SERIALInteger, VARCHAR(n)String(n), DECIMAL(p,s)Numeric(p, s) (preserving precision and scale rather than collapsing to a lossy Float), TIMESTAMPDateTime, UUIDString(36). Unlike the JS/TS generators in this cluster, a foreign key becomes a real, functional ForeignKey('table.column') argument directly inside Column(...) — SQLAlchemy models foreign keys as a column-level constraint, not a separate relation object, so this translation is unambiguous and safe to generate. primary_key=True, autoincrement=True, nullable=False, and unique=True are added from the parsed constraints. Only literal defaults and CURRENT_TIMESTAMP/NOW() (→ default=datetime.utcnow, with from datetime import datetime added automatically) are translated into default= arguments.

Features

  • One class(Base) model per table, with __tablename__ set to the real SQL name
  • Real, working ForeignKey('table.column') generation for referenced columns
  • Numeric(precision, scale) preserved from DECIMAL/NUMERIC instead of a lossy float
  • Literal and utcnow defaults translated; everything else left as a comment
  • Copy or download the generated .py module

Example

Input:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  external_id UUID DEFAULT uuid_generate_v4(),
  name VARCHAR(255) NOT NULL,
  is_active BOOLEAN DEFAULT true
);

CREATE TABLE posts (
  id SERIAL PRIMARY KEY,
  user_id INTEGER NOT NULL REFERENCES users(id),
  title VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Output:

from sqlalchemy import Column, Boolean, DateTime, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

Base = declarative_base()


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True, autoincrement=True)
    external_id = Column(String(36))  # SQL default not translated: uuid_generate_v4()
    name = Column(String(255), nullable=False)
    is_active = Column(Boolean, default=True)


class Post(Base):
    __tablename__ = 'posts'

    id = Column(Integer, primary_key=True, autoincrement=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    title = Column(String(255), nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)

Common errors

A DEFAULT expression the generator doesn't recognize, like uuid_generate_v4(), is left as a # SQL default not translated: uuid_generate_v4() comment rather than a guessed default= value — add the real behavior yourself, e.g. default=lambda: str(uuid.uuid4()) or a server-side default via server_default=text(...). Note that while ForeignKey is generated for you, the higher-level relationship() accessor (e.g. posts = relationship('Post', back_populates='user')) is not — that still requires you to decide the attribute name and back-reference on both classes. The generator also targets the classic declarative_base() API, not SQLAlchemy 2.0's typed Mapped/mapped_column style, so on a 2.0 codebase you'll need to convert the Column(...) lines by hand.

Best practices

Add relationship() calls immediately after pasting the models in, using the generated ForeignKey columns as your map of what needs one. Run alembic revision --autogenerate (or your migration tool of choice) against the models to catch any type mismatch with the real database before applying.

Frequently Asked Questions

Are foreign keys generated with ForeignKey()?

Yes — unlike the JS/TS ORM generators in this cluster, SQLAlchemy's ForeignKey('table.column') is a plain column argument rather than a separate relation object, so it's included directly: Column(Integer, ForeignKey('users.id')). You'll still want to add relationship() calls yourself for the ORM-level convenience accessors.

Does this use the newer SQLAlchemy 2.0 declarative style (Mapped / mapped_column)?

No — it generates the classic declarative_base() + Column(...) style, since it's still the most widely deployed pattern across existing SQLAlchemy 1.x codebases. If your project is on 2.0's typed style, the column definitions translate directly — swap Column(...) for mapped_column(...) and add type hints.

How is DEFAULT CURRENT_TIMESTAMP handled?

As default=datetime.utcnow (a Python callable SQLAlchemy invokes per-insert), with the needed from datetime import datetime added automatically. Other SQL default expressions aren't guessed at — only literal values and this common case are translated.

What Python type backs a DECIMAL(10,2) column?

Numeric(10, 2), preserving both the precision and scale from the original SQL type rather than collapsing to a generic Float, since Numeric maps to Python's Decimal and avoids floating-point rounding issues for currency-like data.