You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
How to use two different metadata properly to connect to two databases? #264
metadata is a class variable metadata: ClassVar[MetaData]
Is the only way to handle multiple metadata is to extend the SQLModel class?
class SQLModel(BaseModel, metaclass=SQLModelMetaclass, registry=default_registry):
# SQLAlchemy needs to set weakref(s), Pydantic will set the other slots values
__slots__ = ("__weakref__",)
__tablename__: ClassVar[Union[str, Callable[..., str]]]
__sqlmodel_relationships__: ClassVar[Dict[str, RelationshipProperty]] # type: ignore
__name__: ClassVar[str]
metadata: ClassVar[MetaData]
...
Is the only way to handle multiple metadata is to extend the SQLModel class?
In my experience there are often more solutions to a problem. I don't even know if extending the class is the right way to do it: I only tested table creation and select. Let us know how it works out for you.
By the way, create_all accepts a list of tables, so you can control which tables are created where by passing different lists to this method. That might also be something for you to try.
Which allows to use an unique Session to process transactions.
I saw that the SQLModel Session class basically wraps the SQLAlchemy's one.
Is it possible to do something like this with only one session for several engines and data models split among these engines as SQLAlchemy allows ?
engine1 = create_engine('postgresql://db1')
engine2 = create_engine('postgresql://db2')
# bind User operations to engine 1, Account operations to engine 2
Session.configure(binds={User:engine1, Account:engine2})
session = Session()
# .... work with accounts and users
session.commit()
Did anyone else ever figure this out? I'm looking to do something similiar (2 different fastapi endpoints using sqlmodel each tied to a different database) but am struggling to find any documentation that would support doing this.
Reacted by cwillhu, gsouveton and Matthieu LAURENT
What a timing @vn7n24fzkq ! I spent the last few days on this and just came to the same solution !
Here is the explanation : SQLModel uses by default a single registry mapper, which means all classes names are gathered in a single namespace, causing name collisions if several databases contain classes with the same name.
Which causes errors like this one :
"sqlalchemy.exc.InvalidRequestError: Multiple classes found for path "xxx" in the registry of this declarative base. Please use a fully module-qualified path."
Specifying a new instance of registry when creating a SQLModel subclass seems the right way to solve this issue.
Reacted by Casper, ChouUn, Alex Kreidler, Matthieu LAURENT, Andrea Ghensi, Haolun Yuan and mkaimTPX
I want a description of the recommended method in the official document.
Reacted by Luke Yates, Bram Swenson, Thomas Palma, Japheth Yates, Alexandr Makurin, Guy Teub, farhanhubble, Vladimir Lebedev, Nicolas Iderhoff, Ceonsamea and 6 more
WRONG!! x10^256 examples of also wrong. Don't mess up the registry
On the right track but forgot something critical. Applying database objects naming convention.
^^^ quoted that so can copy+paste it and get reading ^^^
sqlalchemy docs screams to do this
alembic docs has a whole section dedicated to this topic
So what about SQLModel docs or issues? .... (crickets)
Every example ever lacks applying naming convention to the registry metadata!
from sqlalchemy import MetaData
from sqlalchemy.orm import registry
# copy+paste from the sqlalchemy docs. One case don't wanna be creative.
naming_convention_no_schema = {
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s",
}
metadata = MetaData(
naming_convention=naming_convention_no_schema,
schema=schema,
)
reg = registry(metadata=metadata)
class DB1Base(SQLModel, registry=reg):
Why not to -- job security!
Can only imagine that folks wanting to give every single database object a name manually would do that as a form of job security. If that is the case then carry on.
For those of us who don't want to micro manage the micro manage of micro managers, would highly suggest not manually explicitly naming each and every database object. In each and every database. Not ever, but almost nearly ever.
For example, what if the guy in charge of random database object names gets a girlfriend? It could happen and what a disaster that would be. For him, for her, and for all the people who have to try to track down why a foreign key or unique constraint doesn't exist when it's clear as day in the code that it should be there.
Might have exaggerated, there is no agency of random database object names. But that won't stop the guy in charge of random database object names. Numerically, he can snap his fingers and poof, that agency will exist. Don't underestimate the power and unflinching resolve of the guy in charge of random database object names
schema
schema is str | None. For sharding and tenants you want it to be None.
A bit of trivia, for sqlite, the default schema is "main". For postgresql, it's "public".
The take away
Every single SQLModel Base ever neglects, when creating a registry, to apply database objects naming convention. This includes the SQLModel source code.
In Issues, when writing SQLModel Base(s), have mercy on those who are less knowledgeable by applying the registry correctly.
Activity
byrman commentedon Mar 9, 2022
This seems to work, although I did not test is thoroughly:
murata100 commentedon Mar 10, 2022
Thank you @byrman
I saw the definition of the SQLModel class
metadata is a class variable
metadata: ClassVar[MetaData]Is the only way to handle multiple metadata is to extend the SQLModel class?
https://github.com/tiangolo/sqlmodel/blob/8d1b6f079adad47cc242710f6cb1790a8ad8fbd2/sqlmodel/main.py#L478
byrman commentedon Mar 10, 2022
In my experience there are often more solutions to a problem. I don't even know if extending the class is the right way to do it: I only tested table creation and select. Let us know how it works out for you.
byrman commentedon Mar 10, 2022
By the way,
create_allaccepts a list of tables, so you can control which tables are created where by passing different lists to this method. That might also be something for you to try.murata100 commentedon Mar 10, 2022
For now, I use it with alembic.
I don't use
create_allin production.env.py
Probably, There is no problem to use it with alembic.
But, I'm a little hesitant to use sqlmodel in production..
gsouveton commentedon Jul 12, 2022
I'm facing the same problem. But additionally I would like to work with transactions.
SQLAlchemy allows to do this :
Which allows to use an unique Session to process transactions.
I saw that the SQLModel Session class basically wraps the SQLAlchemy's one.
Is it possible to do something like this with only one session for several engines and data models split among these engines as SQLAlchemy allows ?
cctdev commentedon Sep 12, 2022
Did anyone else ever figure this out? I'm looking to do something similiar (2 different fastapi endpoints using sqlmodel each tied to a different database) but am struggling to find any documentation that would support doing this.
vn7n24fzkq commentedon Nov 10, 2022
I finally found a simple way to create tables in different databases.
gsouveton commentedon Nov 10, 2022
What a timing @vn7n24fzkq ! I spent the last few days on this and just came to the same solution !
Here is the explanation : SQLModel uses by default a single registry mapper, which means all classes names are gathered in a single namespace, causing name collisions if several databases contain classes with the same name.
Which causes errors like this one :
"sqlalchemy.exc.InvalidRequestError: Multiple classes found for path "xxx" in the registry of this declarative base. Please use a fully module-qualified path."
Specifying a new instance of registry when creating a SQLModel subclass seems the right way to solve this issue.
jooh commentedon Jan 12, 2023
This works!
If like me you were struggling to combine this with using inheritance to extend models the solution is to use mixins to patch in columns as in #70
tanaga9 commentedon Apr 9, 2023
I want a description of the recommended method in the official document.
msftcangoblowm commentedon Aug 6, 2025
WRONG!! x10^256 examples of also wrong. Don't mess up the registry
On the right track but forgot something critical. Applying
database objects naming convention.^^^ quoted that so can copy+paste it and get reading ^^^
sqlalchemy docs screams to do this
alembic docs has a whole section dedicated to this topic
So what about SQLModel docs or issues? .... (crickets)
Every example ever lacks applying naming convention to the registry metadata!
Why not to -- job security!
Can only imagine that folks wanting to give every single database object a name manually would do that as a form of job security. If that is the case then carry on.
For those of us who don't want to micro manage the micro manage of micro managers, would highly suggest not manually explicitly naming each and every database object. In each and every database. Not ever, but almost nearly ever.
For example, what if the guy in charge of random database object names gets a girlfriend? It could happen and what a disaster that would be. For him, for her, and for all the people who have to try to track down why a foreign key or unique constraint doesn't exist when it's clear as day in the code that it should be there.
Might have exaggerated, there is no agency of random database object names. But that won't stop the guy in charge of random database object names. Numerically, he can snap his fingers and poof, that agency will exist. Don't underestimate the power and unflinching resolve of the guy in charge of random database object names
schema
schema is
str | None. For sharding and tenants you want it to beNone.A bit of trivia, for sqlite, the default schema is "main". For postgresql, it's "public".
The take away
Every single SQLModel Base ever neglects, when creating a registry, to apply database objects naming convention. This includes the SQLModel source code.
In Issues, when writing SQLModel Base(s), have mercy on those who are less knowledgeable by applying the registry correctly.