Repository navigation
How do you define polymorphic models similar to the sqlalchemy ones? #36
Copy link
Copy link
Closed
Labels
Description
First Check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn't find it.
- I searched the SQLModel documentation, with the integrated search.
- I already searched in Google "How to X in SQLModel" and didn't find any information.
- I already read and followed all the tutorial in the docs and didn't find an answer.
- I already checked if it is not related to SQLModel but to Pydantic.
- I already checked if it is not related to SQLModel but to SQLAlchemy.
Commit to Help
- I commit to help with one of those options 👆
Example Code
from sqlmodel import Relationship, SQLModel, Field, create_engine
from typing import Optional
import uuid
class Principal(SQLModel, table=True):
__tablename__ = "users"
id: Optional[uuid.UUID] = Field(primary_key=True,nullable=False,default_factory=uuid.uuid4)
is_active:bool = Field(default=True)
type: str = Field(default="principal")
__mapper_args__ = {
'polymorphic_on':'type',
'polymorphic_identity':'principal'
}
class User(Principal,table=True):
email: str
__mapper_args__ = {
'polymorphic_identity':'user'
}
class ServiceUser(Principal,table=True):
name: str
owner_id: Optional[uuid.UUID] = Field(default=None, foreign_key=('users.id'))
owner: "User" = Relationship()
__mapper_args__ = {
'polymorphic_identity':'serviceuser'
}
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
SQLModel.metadata.create_all(engine)Description
- Run the code above
- Look at the echo from the database:
<excluded for brevity>
2021-08-26 21:21:45,820 INFO sqlalchemy.engine.Engine
CREATE TABLE users (
id CHAR(32) NOT NULL,
is_active BOOLEAN,
type VARCHAR,
PRIMARY KEY (id)
)
<excluded for brevity>
- Sit back and wonder why the inherited objects fields are not included (notice the create table statement not including the fields)
Operating System
Windows
Operating System Details
No response
SQLModel Version
0.0.4
Python Version
3.8.10
Additional Context
I think I can fall back to sqlalchemy in this case without any problems, but maybe I am at a loss and it should be done in another way. Removing the "table=True" from the inherited classes makes no difference. Maybe this is also an edge case that should not be supported, but anyway it would be nice to see how this should be handled by people smarter than me. I am currently evaluating rewriting a backend to sqlmodel as it is already implemented in FastApi (which is amazing), and although I know it's early days for this project, I like what it tries to achieve :)
Reactions are currently unavailable
Activity
movabo commentedon Jan 20, 2022
I found a workaround/hack on how to allow Single Table Inheritance as mentioned by you (Joined Table Inheritance does not work):
My example refers to the SQLAlchemy example but should work with your code as well:
The
CustomMetaclassbasically disables this check and thus allows the inheritance.It might break some FastAPI functionality as the comment in the code of the check suggests.
Because this is a hack it would be great if we could add an officially supported way of disabling this check to support (at least) single table inheritance. It seems to work well outside of FastAPI (I did not test it with FastAPI).
I see two ways in doing this:
class Employee(SQLModel, table=True, allow_derived_tables=True):)__mapper_args__.["polymorphic_identity"]is set in all bases which are also tables and only if also the__tablename__is the same across the bases (to only allow single table inheritance).@tiangolo, would you accept a PR with one of the two ideas? If yes, which one would you prefer? Then I would prepare a PR. :)
shatteringlass commentedon Feb 20, 2022
I tried this but it didn't seem to work for me on sqlmodel 0.0.6.
Anyway, my project aims to use FastAPI so I am more interested in a proper solution rather than a workaround.
Is this by any chance on the roadmap @tiangolo?
Thanks a bunch!
BigTMiami commentedon Mar 14, 2022
I would find this very useful as well.
jkehrbaum commentedon Mar 18, 2022
Dear all, is there any workaround available for having polymorphic models? The code from movabo doesn’t seem to work within the latest version of SQLModel. Any ideas or plans to have it in future releases?
thx a lot
shatteringlass commentedon Mar 18, 2022
I had posted my solution/workaround here:
https://matrix.to/#/!MYdZNkXpgAXqXRdstX:gitter.im/$cqBN6h_4QSiFRgjivn6rh3lsHAZIdDwvYLlwL8otP8s?via=gitter.im&via=matrix.org&via=averyan.ru
It's not super generic, but it could be useful to other people here as well, so here's the copypasta:
LaQuay commentedon Nov 9, 2022
Hi, I am struggling with this problem as well. The proposals provided here don't work either for me.
@shatteringlass Thanks but your "solution" is for FastAPI + SQLAlchemy, with no SQLModel involved in your code. This issue is for FastAPI + SQLModel.
Any ideas? Thanks
DrOncogene commentedon Apr 13, 2023
Hello
This is still not working. From my own end, I noticed the problem is not really the polymorphic inheritance.
It is that SQLModel does not support model inheritance that is more than one layer deep, regardless of whether it is polymorphic or not.
I really need this to work for a project I'm currently working on as I want to use it with FastAPI. Thank you
andruli commentedon Sep 12, 2023
I have a very ugly but working workaround for
0.0.8for single table and joined inheritance.I started from @movabo's answer, sadly that no longer works.
@DrOncogene was also correct, the problem is SQLModel doesn't allow inheritance of tables.
The things the workaround does:
used_dictthat doesn't include the properties of the part models (to avoid the duplicate field errors)DeclarativeMetathat repects the fields we sent since by default it automatically overrides thatAll in all, this is the workaround
And you'd use it like this for joined inheritance
And this for single table inheritance
And you'd use it like this for joined inheritance
It looks like a lot of code, but it's mostly because I needed to copy the original metaclasses and just do a few modifications here and there. The actual changes are very little (<10 lines).
PS. This is a workaround and code WILL MOST LIKELY BREAK when either SQLModel or SQLAlchemy update.
bosukas commentedon Dec 17, 2023
Any updates on this one?
hslira commentedon Apr 17, 2024
just checking
fsackur commentedon Jun 1, 2024
I can't really use metaclasses for my app, so here's an ugly workaround for joined inheritance. I prefer the code from @andruli .
v0.0.18.
schema
emitted warnings
ixycoexzckwpmlcu commentedon Sep 1, 2024
I couldn't find a solution for single table inheritance for SQLModel 0.0.22, so I implemented my own solution here.
Maybe related: #438, #488
PaleNeutron commentedon Nov 27, 2024
I have implement this feature in #1226 .
Can any maintainer review that? @tiangolo
heitorslira commentedon Feb 14, 2026
any updates on this being merged?