11# sqlalchemy-to-ormar
22
3- # ** WORK IN PROGRESS**
4-
5- Simple translator from ` sqlalchemy ` ORM models to ` ormar ` models.
3+ A simple auto-translator from ` sqlalchemy ` ORM models to ` ormar ` models.
64
75The ` ormar ` package is an async mini ORM for Python, with support for ** Postgres,
8- MySQL** , and ** SQLite** .
6+ MySQL** , and ** SQLite** .
97
108To learn more about ormar:
119
12- * ormar [ github] [ github ]
13- * ormar [ documentation] [ documentation ]
10+ * ormar [ github] [ github ]
11+ * ormar [ documentation] [ documentation ]
12+
13+ ## Quickstart
14+
15+ ``` python
16+ from databases import Database
17+ from sqlalchemy import (
18+ Column,
19+ ForeignKey,
20+ Integer,
21+ MetaData,
22+ String,
23+ create_engine,
24+ DECIMAL ,
25+ )
26+ from sqlalchemy.ext.declarative import declarative_base
27+ from sqlalchemy.orm import Session, relationship, sessionmaker
28+
29+ Base = declarative_base()
30+ Database_URL = " sqlite:///test.db"
31+ engine = create_engine(Database_URL, echo = True )
32+
33+
34+ # given sqlalchemy models you already have
35+ class User (Base ):
36+ __tablename__ = " users"
37+
38+ id = Column(Integer, primary_key = True )
39+ name = Column(String)
40+ fullname = Column(String)
41+ nickname = Column(String)
42+ salary = Column(DECIMAL )
43+
44+ addresses = relationship(
45+ " Address" , back_populates = " user" , cascade = " all, delete, delete-orphan"
46+ )
47+
48+
49+ class Address (Base ):
50+ __tablename__ = " addresses"
51+ id = Column(Integer, primary_key = True )
52+ email_address = Column(String, nullable = False )
53+ user_id = Column(Integer, ForeignKey(" users.id" ))
54+
55+ user = relationship(" User" , back_populates = " addresses" )
56+
57+
58+ # instantiate new Databases instance
59+ database = Database(Database_URL)
60+ # note that you need new metadata instance as table names in ormar
61+ # will remain the same and you cannot have two tables with same name in
62+ # one metadata, note that we bind it to the same engine!
63+ # (or you can create new one with same url)
64+ metadata = MetaData(engine)
65+
66+ # use sqlalchemy-to-ormar (not normally imports should be at the top)
67+ from sqlalchemy_to_ormar import ormar_model_str_repr, sqlalchemy_to_ormar
68+
69+ # convert sqlalchemy models to ormar
70+ OrmarAddress = sqlalchemy_to_ormar(Address, database = database, metadata = metadata)
71+ OrmarUser = sqlalchemy_to_ormar(User, database = database, metadata = metadata)
72+
73+ # you can print the ormar model
74+ # or save it to file and you have proper model definition created for you
75+
76+ address_str = ormar_model_str_repr(OrmarAddress)
77+
78+ # now you can print it or save to file
79+ print (address_str)
80+ # will print:
81+
82+ # class OrmarAddress(ormar.Model):
83+ #
84+ # class Meta(ormar.ModelMeta):
85+ # metadata=metadata
86+ # database=database
87+ # tablename="addresses"
88+ #
89+ # id = ormar.Integer(autoincrement=True, primary_key=True)
90+ # email_address = ormar.String(max_length=255, nullable=False)
91+ # user = ormar.ForeignKey(to=OrmarUser, related_name="addresses", name=user_id, nullable=True)
92+
93+ # if you want to skip column aliases if they match field names use skip_names_if_match flag
94+ user_model_str = ormar_model_str_repr(OrmarUser, skip_names_if_match = True )
95+
96+ # let's insert some sample data with sync sqlalchemy
97+
98+ Base.metadata.create_all(engine)
99+ LocalSession = sessionmaker(bind = engine)
100+ db: Session = LocalSession()
101+
102+ ed_user = User(name = " ed" , fullname = " Ed Jones" , nickname = " edsnickname" )
103+ address = Address(email_address = " ed@example.com" )
104+ address2 = Address(email_address = " eddy@example.com" )
105+ ed_user.addresses = [address, address2]
106+
107+ db.add(ed_user)
108+ db.commit()
109+
110+ # and now we can query it asynchronously with ormar
111+ async def test_ormar_queries ():
112+ user = await OrmarUser.objects.select_related(" addresses" ).get(name = ' ed' )
113+ assert len (user.addresses) == 2
114+ assert user.nickname == ' edsnickname'
115+ assert user.fullname == ' Ed Jones'
116+
117+ addresses = await OrmarAddress.objects.select_related(' user' ).all(user__name = ' ed' )
118+ assert len (addresses) == 2
119+ assert addresses[0 ].user.nickname == ' edsnickname'
120+ assert addresses[1 ].user.nickname == ' edsnickname'
121+
122+ # run async
123+ import asyncio
124+ asyncio.run(test_ormar_queries())
125+
126+ # drop db
127+ Base.metadata.drop_all(engine)
128+ ```
129+
130+ ## Automap support
131+
132+ TBD -> translated from models auto-mapped by sqlalchemy
14133
15134## Supported fields
16135
17- ` sqlalchemy-to-ormar ` supports following sqlachemy field types:
136+ ` sqlalchemy-to-ormar ` supports following sqlalchemy field types:
18137
19138* "integer": ` ormar.Integer ` ,
20139* "small_integer": ` ormar.Integer ` ,
@@ -31,16 +150,19 @@ To learn more about ormar:
31150## Supported relations
32151
33152sqlalchemy-to-ormar supports both ` ForeignKey ` as well as ` ManyToMany ` relations
153+ although like ` ormar ` itself it will create relation field on one side of the relation only
154+ and other side will be auto-populated with reversed side.
34155
35156## Known limitations
36157
37158sqlalchemy to ormar right now does not support:
38159
39- * composite (multi-column) primary keys and foreign keys (as ormar does not support
40- them yet)
160+ * composite (multi-column) primary keys and foreign keys (as ormar does not support them
161+ yet)
162+ * ` cascade ` options from ` relationship ` are ignored, only the ones declared in sqlalchemy ForeignKey (ondelete, onupdate) are extracted
41163* ManyToMany fields names customization (as ormar does not support them yet)
164+ * ManyToMany association table has to have primary key
42165* Model inheritance
43166
44-
45167[ documentation ] : https://collerek.github.io/ormar/
46168[ github ] : https://github.com/collerek/ormar
0 commit comments