Reputation: 714
I'm using SQLAlchemy for the first time and trying to define my models / schema. My only experience with ORM prior to this was with Rails and ActiveRecord.
Anyway, following SQLAlchemy's ORM Quick Start, this is the basic example they use (I have removed a few lines which are not relevant to my question):
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user_account"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(30))
addresses: Mapped[list["Address"]] = relationship(
back_populates="user", cascade="all, delete-orphan"
)
class Address(Base):
__tablename__ = "address"
id: Mapped[int] = mapped_column(primary_key=True)
email_address: Mapped[str]
user_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
user: Mapped["User"] = relationship(back_populates="addresses")
My question is: is it possible to create two models in separate files (user.py
and address.py
), defining each model in its own file, and then import them and run a command like the following in order to instantiate the database:
from sqlalchemy import create_engine
engine = create_engine("sqlite://", echo=True)
Base.metadata.create_all(engine)
Upvotes: 0
Views: 2425
Reputation: 822
I would like to extend on Brian's answer. When using an approach similar to his, I ran into an ImportError: cannot import name 'ModelBase' from partially initialized module 'lib' (most likely due to a circular import)
.
I just made a really quick change that did remove this error, by simply switching the order of ModelBase
declaration and models imports in __init__.py
:
# models.__init__.py
from sqlalchemy.orm import DeclarativeBase
class ModelBase(DeclarativeBase):
pass
from .user import User
from .address import Address
Upvotes: 2
Reputation: 2235
Yes -- what you are asking is both possible and is the standard way of creating SQLAlchemy Schemas.
The only gotcha is that you want all of your models to inherit from the same DeclarativeBase
. This is essentially what registers them with SQLAlchemy and other plugins/tools like Alembic.
There are a few organization structures you can use, but a simple and common one is something like this:
- project_root
- models
+ __init__.py
+ user.py
+ address.py
- utils
- scripts
In models.__init__
, create and export your Base (I'd recommend giving it a slightly more specific name, such as ModelBase
). Then in each of your model files, just import ModelBase
and cut/paste your existing code.
Some projects enforce a single model per file. Others group related models together.
Since all of your models import and use a single DeclaritiveBase
, you can call methods like BaseModel.metadata.create_all()
. Just keep in mind you will still need to import those actual models somewhere.
An easy way to handle that is to import them inside of models.__init__.py
. That way you will essentially load them whenever you import and use ModelBase
.
# models.__init__.py
from .user import User
from .address import Address
class ModelBase(DeclarativeBase):
pass
Upvotes: 2