Subclass identification error on a one to one relationship. #1300
-
| First Check
 Commit to Help
 Example Codefrom pydantic import BaseModel, computed_field, HttpUrl, model_serializer, model_validator
from typing import Annotated, Optional, Any, Self
from sqlalchemy.orm import Relationship
from sqlmodel import SQLModel, Field, BigInteger, AutoString
class Color(BaseModel):
    red: int
    green: int
    blue: int
class User(SQLModel, table=True):
    id: int = Field(primary_key=True, sa_type=BigInteger)
    name: str
    habitue: Optional["Habitue"] = Relationship(back_populates="user",uselist=False)
    streamer: Optional["Streamer"] = Relationship(back_populates="user",uselist=False)
class Habitue(SQLModel, table=True):
    id_: int | None = Field(primary_key=True, default=None)
    user_id: int = Field(foreign_key="user.id", sa_type=BigInteger)
    color: Color = Field(sa_type=AutoString)
    user: User = Relationship(back_populates="habitue")
class Streamer(SQLModel, table=True):
    id_: int | None = Field(primary_key=True, default=None)
    user_id: int = Field(foreign_key="user.id", sa_type=BigInteger)
    url: HttpUrl
    user: User = Relationship(back_populates="streamer")We wanted to be as close as possible to this scenario, even if it's not the best way to do it with sql: CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name TEXT NOT NULL
);
CREATE TABLE habitue (
    id_ SERIAL PRIMARY KEY,
    user_id BIGINT UNIQUE NOT NULL,
    color TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
);
CREATE TABLE streamer (
    id_ SERIAL PRIMARY KEY,
    user_id BIGINT UNIQUE NOT NULL,
    url TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
);DescriptionWe have a User class with an Id and a name.To represent whether this user is a “Streamer” or a “Habitue”, we've defined two other classes with their own attributes. For us, a “User” has the optional ability to be a “Habitue” (A "Habitue" has a color) and/or a “Streamer” (a "Streamer" has a url). We therefore try to represent this link between a basic “User” and its advanced versions via a One-to-One relationship. We realize that at runtime, a type comparison is made. The “Streamer” and “Habitue” classes are not recognized as subclasses of the SQLModel type, but as Enums.As a result, we are unable to establish this One-to-One relationship. To try to solve this, we tried the recommendations provided in: 
 Operating SystemLinux Operating System DetailsI'm running it in a python3.13 image docker SQLModel Version0.0.22 Python VersionPython 3.13.2 Additional ContextFull StackTrace:  | 
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
| You should import  And then pass  from sqlmodel import Relationship
...
    habitue: Optional["Habitue"] = Relationship(back_populates="user", sa_relationship_kwargs={"uselist": False})
    streamer: Optional["Streamer"] = Relationship(back_populates="user", sa_relationship_kwargs={"uselist": False})Runnable code example in the details: from typing import Optional
from pydantic import BaseModel
from sqlmodel import (
    AutoString,
    BigInteger,
    Field,
    Relationship,
    SQLModel,
    create_engine,
)
class Color(BaseModel):
    red: int
    green: int
    blue: int
class User(SQLModel, table=True):
    id: int = Field(primary_key=True, sa_type=BigInteger)
    name: str
    habitue: Optional["Habitue"] = Relationship(
        back_populates="user", sa_relationship_kwargs={"uselist": False}
    )
    streamer: Optional["Streamer"] = Relationship(
        back_populates="user", sa_relationship_kwargs={"uselist": False}
    )
class Habitue(SQLModel, table=True):
    id_: int | None = Field(primary_key=True, default=None)
    user_id: int = Field(foreign_key="user.id", sa_type=BigInteger)
    color: Color = Field(sa_type=AutoString)
    user: User = Relationship(back_populates="habitue")
class Streamer(SQLModel, table=True):
    id_: int | None = Field(primary_key=True, default=None)
    user_id: int = Field(foreign_key="user.id", sa_type=BigInteger)
    ...
    user: User = Relationship(back_populates="streamer")
engine = create_engine(
    "postgresql://user:mysecretpassword@localhost/some_db", echo=True
)
SQLModel.metadata.drop_all(engine)
SQLModel.metadata.create_all(engine) | 
Beta Was this translation helpful? Give feedback.
You should import
Relationshipfrom sqlmodel, not from sqlalchemy.And then pass
uselistviasa_relationship_kwargs:Runnable code example in the details: