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

Non-sqlalchemy types unable to be defined in base data models #469

Closed
8 tasks done
jtpavlock opened this issue Oct 16, 2022 · 4 comments
Closed
8 tasks done

Non-sqlalchemy types unable to be defined in base data models #469

jtpavlock opened this issue Oct 16, 2022 · 4 comments
Labels
answered question Further information is requested

Comments

@jtpavlock
Copy link

jtpavlock commented Oct 16, 2022

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

#!/usr/bin/env python3

from typing import Optional, Any

import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.mutable import MutableDict, MutableSet
from sqlalchemy.orm import sessionmaker
from sqlalchemy import JSON, Column
from sqlmodel import SQLModel, Field, create_engine, Relationship

Session = sessionmaker()
Base = declarative_base()


class BaseTrack(SQLModel):
    title: str


class Track(BaseTrack, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    title: int
    album_id: Optional[int] = Field(default=None, foreign_key="album.id")
    album: "Album" = Relationship(back_populates="tracks")


class BaseAlbum(SQLModel):
    tracks: list[BaseTrack]


class Album(BaseAlbum, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    tracks: Optional[list[Track]] = Relationship(back_populates="album")


engine = create_engine("sqlite:///:memory:")
Session.configure(bind=engine)
SQLModel.metadata.create_all(engine)
session = Session()

track = Track(id=1, title=2, album_id=1, album=Album(id=1))

session.add(track)
session.commit()

Description

The above code gives the following error:

Traceback (most recent call last):
  File "/home/jacob/src/Moe/test_custom.py", line 31, in <module>
    class Album(BaseAlbum, table=True):
  File "/home/jacob/src/Moe/.venv/lib/python3.9/site-packages/sqlmodel/main.py", line 293, in __new__
    col = get_column_from_field(v)
  File "/home/jacob/src/Moe/.venv/lib/python3.9/site-packages/sqlmodel/main.py", line 421, in get_column_from_field
    sa_type = get_sqlachemy_type(field)
  File "/home/jacob/src/Moe/.venv/lib/python3.9/site-packages/sqlmodel/main.py", line 414, in get_sqlachemy_type
    raise ValueError(f"The field {field.name} has no matching SQLAlchemy type")
ValueError: The field tracks has no matching SQLAlchemy type

Because I'm overriding tracks to be a column in my actual database class, this should not error.

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.08

Python Version

3.9.13

Additional Context

Looks to have been caused by #18

@jtpavlock jtpavlock added the question Further information is requested label Oct 16, 2022
@antont
Copy link

antont commented Oct 21, 2022

Why do you want to have the relationship in the base? I've simply omitted them from there, as inherit Base to the Create models, which are the POST data that the frontend uses to create objects. Then Read models have such definitions for the relationships that we wanna expose in the API.

@jtpavlock
Copy link
Author

I'm using the base model to represent a subset of data useful for certain operations that don't require connection to a database or the entire model to be present.

@tiangolo
Copy link
Owner

Yep, you shouldn't do that. If a descendant of the base class is completely overriding the field, then it should probably not be there. In this particular case, it should certainly not be there on the base class.

You would have one field for the table model and another field for the class that inherits from base that needs the relationship.

If you want to avoid duplicating the field with relationships you would need a base for everything, and another "sub-base" only for data models (not tables) that includes the relationship.

@github-actions
Copy link

github-actions bot commented Nov 1, 2022

Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.

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

No branches or pull requests

3 participants