Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use original type hint by defining relationship #228

Open
8 tasks done
Whitroom opened this issue Jan 19, 2022 · 5 comments
Open
8 tasks done

Unable to use original type hint by defining relationship #228

Whitroom opened this issue Jan 19, 2022 · 5 comments
Labels
question Further information is requested

Comments

@Whitroom
Copy link

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 typing import Optional

from sqlmodel import Field, SQLModel, Relationship, create_engine, Session

class Team(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    headquarters: str

    # key sentence
    heroes: list["Hero"] = Relationship(back_populates='team')

class Hero(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    secret_name: str
    age: Optional[int] = Field(default=None, index=True)

    team_id: Optional[int] = Field(default=None, foreign_key=Team.id)

database_url = f'mysql+mysqlconnector://{user}:{password}@{host}/{database_name}'

engine = create_engine(database_url, encoding='utf8', echo=True)

if __name__ == '__main__':
    SQLModel.metadata.create_all(engine)

Description

I create Hero and Team models and try to use python original type hint, but while running it, it occurs exceptions...

Traceback (most recent call last):
File "pydantic\validators.py", line 709, in pydantic.validators.find_validators
TypeError: issubclass() arg 1 must be a class

Traceback (most recent call last):
File "C:\Users\10620\Desktop\Code\Python\sqlmodel\table_relationship.py", line 5, in
class Team(SQLModel, table=True):
File "C:\Users\10620\AppData\Local\Programs\Python\Python310\lib\site-packages\sqlmodel\main.py", line 342, in init
temp_field = ModelField.infer(
File "pydantic\fields.py", line 488, in pydantic.fields.ModelField.infer
File "pydantic\fields.py", line 419, in pydantic.fields.ModelField.init
File "pydantic\fields.py", line 534, in pydantic.fields.ModelField.prepare
File "pydantic\fields.py", line 728, in pydantic.fields.ModelField._type_analysis
File "pydantic\fields.py", line 778, in pydantic.fields.ModelField._create_sub_type
File "pydantic\fields.py", line 419, in pydantic.fields.ModelField.init
File "pydantic\fields.py", line 539, in pydantic.fields.ModelField.prepare
File "pydantic\fields.py", line 801, in pydantic.fields.ModelField.populate_validators
File "pydantic\validators.py", line 718, in find_validators
RuntimeError: error checking inheritance of 'Hero' (type: str)

The solution is adding List from typing and replacing it, but I don't know how to solve this bug...

link: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/

Operating System

Windows

Operating System Details

No response

SQLModel Version

0.0.6

Python Version

3.10.1

Additional Context

No response

@Whitroom Whitroom added the question Further information is requested label Jan 19, 2022
@byrman
Copy link
Contributor

byrman commented Jan 31, 2022

I am not sure I understand your question correctly, but here list["Hero"] should indeed be List["Hero"]. From Python 3.9 onwards, generic list[Hero] should work as well, I think, but that requires your code to be rearranged, so that Hero is defined before Team.

@aleksul
Copy link

aleksul commented May 19, 2022

@Whitroom pls update to pydantic v1.9.1 - it should be fixed

@Shuntw6096
Copy link

Shuntw6096 commented Mar 7, 2024

I meet a similar problem,

class Base(SQLModel):
    pass
class Test:
    basemodel = Base # type alias at here, classVar[type[Base]] also didn't work
    __slots__ = 'filename', 'datamodel'
    def __init__(self, filename: str, datamodel: Optional[Base] = None, **kwargs):
        self.filename = filename
        if datamodel is not None:
            assert isinstance(datamodel, self.basemodel) # self.basemodel is Any at here, should be type[Base]
            self.datamodel = datamodel
        else:
            self.datamodel = self.basemodel(**kwargs) # self.basemodel is Any at here, should be type[Base]

If you remove inheritance of Base, typehint work perfectly.
My stupid solution is adding a classmethod to get instance of Base,

class Base(SQLModel, table=True):
    @classmethod
    def get_instance(cls, data: dict):
        return Base(**data)


class Test:
    basemodel = Base.get_instance
    __slots__ = 'filename', 'datamodel'
    def __init__(self, filename: str, datamodel: Optional[Base] = None, **kwargs):
        self.filename = filename
        if datamodel is not None:
            assert isinstance(datamodel, self.basemodel)
            self.datamodel = datamodel
        else:
            self.datamodel = self.basemodel(**kwargs)

Btw, filename is private attribute of Base at first, but idk how to init it.

@thribhu
Copy link

thribhu commented Sep 30, 2024

Many to one relationship using sqlmodel and sqlalchemy along with alembic

When initializing mapper Mapper[Category(category)], expression "relationship("Mapped[List['SubCategory']]")" seems to be using a generic class as the argument to relationship(); please state the generic argument using an annotation, e.g. "subcategories: Mapped[Mapped[List['SubCategory']']] = relationship()\

I am facing an issue with many to one relationship. Having followed the official documentation, I created my relationship attributes inside my table.
However, I receive an error from sqlalchemy like the above. My code is simple

from sqlmodel import SQLModel
from sqlmodel import Field
from sqlmodel import Relationship
from typing import Optional
from typing import List

class Category(SQLModel, table=True):
  id: int | None = Field(default=None, primary_key=True)
  name: str = Field(..., title="Category name")
  subcategories: List['SubCategory'] = Relationship(back_populates='category')
 
class SubCategory(SQLModel, table=True):
  id: int | None = Field(default=None, primary_key=True)
  name: str = Field(..., title="Sub category name")
  category_id: int | None = Field(default=None, foreign_key='category.id')
  category: 'Category' | None = Relationship(back_populates='subcategories')

@nicksonthc
Copy link

nicksonthc commented Nov 14, 2024

Some updates here: I tested the tutorial code with the sample provided and found that using from future import annotations might cause a mapper error. After removing the import, it worked.

class Team(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    headquarters: str

    heroes: list["Hero"] = Relationship(back_populates="team")


class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str = Field(index=True)
    secret_name: str
    age: int | None = Field(default=None, index=True)

    team_id: int | None = Field(default=None, foreign_key="team.id")
    team: Team | None = Relationship(back_populates="heroes")

Import annotations might cause the mapper error

If in my model file got import annotations, then i will get the mappers error, after i remove from __future__ import annotations
from __future__ import annotations

Error
image

Tutorial i refer to - https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/#declare-relationship-attributes

Context & Environments

python 3.12
pydantic==2.9.2
SQLAlchemy==2.0.35
sqlmodel==0.0.22

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

6 participants