Omymodels
O!My Models (omymodels) is a library to generate Pydantic, Dataclasses, GinoORM Models, SqlAlchemy ORM, SqlAlchemy Core Table, Models from SQL DDL. And convert one models to another.
Install / Use
/learn @xnuinside/OmymodelsREADME
O! My Models
Interactive Demo | Documentation | PyPI
Try in Web-UI
Try the online O!MyModels converter or simply use it online: https://archon-omymodels-online.hf.space/ (A big thanks for that goes to https://github.com/archongum)
Examples
You can find usage examples in the example/ folder on GitHub: https://github.com/xnuinside/omymodels/tree/main/example
About library
O! My Models (omymodels) is a library that allow you to generate different ORM & pure Python models from SQL DDL or convert one models type to another (exclude SQLAlchemy Table, it does not supported yet by py-models-parser).
Supported Models:
- SQLAlchemy 2.0 ORM (https://docs.sqlalchemy.org/en/20/orm/) - modern syntax with
Mappedandmapped_column - SQLAlchemy ORM (legacy style)
- SQLAlchemy Core (Tables) (https://docs.sqlalchemy.org/en/20/core/metadata.html)
- SQLModel (https://sqlmodel.tiangolo.com/) - combines SQLAlchemy and Pydantic
- GinoORM (https://python-gino.org/)
- Pydantic v1/v2 (https://docs.pydantic.dev/)
- Python Dataclasses (https://docs.python.org/3/library/dataclasses.html)
- Python Enum (https://docs.python.org/3/library/enum.html) - generated from DDL SQL Types
- OpenAPI 3 (Swagger) schemas (https://swagger.io/specification/)
How to install
pip install omymodels
How to use
From Python code
Create Models from DDL
By default method create_models generates GinoORM models. Use the argument models_type to specify output format:
'pydantic'- Pydantic v1 models (usesOptional[X])'pydantic_v2'- Pydantic v2 models (usesX | Nonesyntax,dict | listfor JSON)'sqlalchemy'- SQLAlchemy ORM models'sqlalchemy_core'- SQLAlchemy Core Tables'dataclass'- Python Dataclasses'sqlmodel'- SQLModel models'openapi3'- OpenAPI 3 (Swagger) schema definitions
A lot of examples in tests/ - https://github.com/xnuinside/omymodels/tree/main/tests.
Pydantic v1 example
from omymodels import create_models
ddl = """
CREATE table user_history (
runid decimal(21) null
,job_id decimal(21) null
,id varchar(100) not null
,user varchar(100) not null
,status varchar(10) not null
,event_time timestamp not null default now()
,comment varchar(1000) not null default 'none'
) ;
"""
result = create_models(ddl, models_type='pydantic')['code']
# output:
import datetime
from typing import Optional
from pydantic import BaseModel
class UserHistory(BaseModel):
runid: Optional[int]
job_id: Optional[int]
id: str
user: str
status: str
event_time: datetime.datetime
comment: str
Pydantic v2 example
from omymodels import create_models
ddl = """
CREATE table user_history (
runid decimal(21) null
,job_id decimal(21) null
,id varchar(100) not null
,user varchar(100) not null
,status varchar(10) not null
,event_time timestamp not null default now()
,comment varchar(1000) not null default 'none'
) ;
"""
result = create_models(ddl, models_type='pydantic_v2')['code']
# output:
from __future__ import annotations
import datetime
from pydantic import BaseModel
class UserHistory(BaseModel):
runid: float | None = None
job_id: float | None = None
id: str
user: str
status: str
event_time: datetime.datetime = datetime.datetime.now()
comment: str = 'none'
Key differences in Pydantic v2 output:
- Uses
X | Noneinstead ofOptional[X] - Uses
dict | listfor JSON/JSONB types instead ofJson - Includes
from __future__ import annotationsfor Python 3.9 compatibility - Nullable fields automatically get
= Nonedefault
To generate Dataclasses from DDL use argument models_type='dataclass'
for example:
# (same DDL as in Pydantic sample)
result = create_models(ddl, schema_global=False, models_type='dataclass')['code']
# and result will be:
import datetime
from dataclasses import dataclass
@dataclass
class UserHistory:
id: str
user: str
status: str
runid: int = None
job_id: int = None
event_time: datetime.datetime = datetime.datetime.now()
comment: str = 'none'
GinoORM example. If you provide an input like:
CREATE TABLE "users" (
"id" SERIAL PRIMARY KEY,
"name" varchar,
"created_at" timestamp,
"updated_at" timestamp,
"country_code" int,
"default_language" int
);
CREATE TABLE "languages" (
"id" int PRIMARY KEY,
"code" varchar(2) NOT NULL,
"name" varchar NOT NULL
);
and you will get output:
from gino import Gino
db = Gino()
class Users(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer(), autoincrement=True, primary_key=True)
name = db.Column(db.String())
created_at = db.Column(db.TIMESTAMP())
updated_at = db.Column(db.TIMESTAMP())
country_code = db.Column(db.Integer())
default_language = db.Column(db.Integer())
class Languages(db.Model):
__tablename__ = 'languages'
id = db.Column(db.Integer(), primary_key=True)
code = db.Column(db.String(2))
name = db.Column(db.String())
From cli
omm path/to/your.ddl
# for example
omm tests/test_two_tables.sql
You can define target path where to save models with -t, --target flag:
# for example
omm tests/test_two_tables.sql -t test_path/test_models.py
If you want generate the Pydantic or Dataclasses models - just use flag -m or --models_type='pydantic' / --models_type='dataclass'
omm /path/to/your.ddl -m dataclass
# or
omm /path/to/your.ddl --models_type pydantic
Small library is used for parse DDL- https://github.com/xnuinside/simple-ddl-parser.
What to do if types not supported in O!MyModels and you cannot wait until PR will be approved
First of all, to parse types correct from DDL to models - they must be in types mypping, for Gino it exitst in this file:
omymodels/gino/types.py types_mapping
If you need to use fast type that not exist in mapping - just do a path before call code with types_mapping.update()
for example:
from omymodels.models.gino import types
from omymodels import create_models
types.types_mapping.update({'your_type_from_ddl': 'db.TypeInGino'})
ddl = "YOUR DDL with your custom your_type_from_ddl"
models = create_models(ddl)
#### And similar for Pydantic types
from omymodels.models.pydantic import types types_mapping
from omymodels import create_models
types.types_mapping.update({'your_type_from_ddl': 'db.TypeInGino'})
ddl = "YOUR DDL with your custom your_type_from_ddl"
models = create_models(ddl, models_type='pydantic')
Schema defenition
There is 2 ways how to define schema in Models:
- Globally in Gino() class and it will be like this:
from gino import Gino
db = Gino(schema="schema_name")
And this is a default way for put schema during generation - it takes first schema in tables and use it.
- But if you work with tables in different schemas, you need to define schema in each model in table_args. O!MyModels can do this also. Just use flag
--no-global-schemaif you use cli or put argument 'schema_global=False' to create_models() function if you use library from code. Like this:
ddl = """
CREATE TABLE "prefix--schema-name"."table" (
_id uuid PRIMARY KEY,
one_more_id int
);
create unique index table_pk on "prefix--schema-name"."table" (one_more_id) ;
create index table_ix2 on "prefix--schema-name"."table" (_id) ;
"""
result = create_models(ddl, schema_global=False)
And result will be this:
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.schema import UniqueConstraint
from sqlalchemy import Index
from gino import Gino
db = Gino()
class Table(db.Model):
__tablename__ = 'table'
_id = db.Column(UUID, primary_key=True)
one_more_id = db.Column(db.Integer())
__table_args__ = (
UniqueConstraint(one_more_id, name='table_pk'),
Index('table_ix2', _id),
dict(schema="prefix--schema-name")
)
OpenAPI 3 (Swagger) Support
O!MyModels supports bidirectional conversion with OpenAPI 3 schemas.
Generate OpenAPI 3 schema from DDL
from omymodels import create_models
ddl = """
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(255),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP
);
"""
result = create_models(ddl, models_type="openapi3")
print(result["code"])
# Output:
# {
# "components": {
# "schemas": {
# "Users": {
# "type": "object",
# "properties": {
# "id": {"type": "integer"},
# "username": {"type": "string", "maxLength": 100},
# "email": {"type": "string", "maxLength": 255},
# "is_active": {"type": "boolean", "default": true},
# "created_at": {"type": "string", "format": "date-time"}
# },
# "required": ["id", "username"]
# }
# }
# }
# }
