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

No support for SQLModel relationships #160

Closed
2 tasks done
jakub-borusewicz opened this issue May 30, 2022 · 2 comments
Closed
2 tasks done

No support for SQLModel relationships #160

jakub-borusewicz opened this issue May 30, 2022 · 2 comments
Labels

Comments

@jakub-borusewicz
Copy link

Checklist

  • The bug is reproducible against the latest release or master.
  • There are no similar issues or pull requests to fix it yet.

Describe the bug

SQLModel does not store relationships data directly in attributes, so trying to use them like vanilla SQLAlchemy attributes like that

class ModelA(SQLModel, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)
    

class ModelB(SQLModel, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)
    model_a: Optional[ModelA] = Relationship(sa_relationship=relationship("ModelA"))


class ModelBAdmin(ModelAdmin, model=ModelB):
    column_list = [ModelB.model_a]

results in error:

AttributeError: type object 'ModelB' has no attribute 'model_a'

Trying to use attribute used by SQLModel does not work either:

class ModelBAdmin(ModelAdmin, model=ModelB):
    column_list = [ModelB.__sqlmodel_relationships__["model_a"].sa_relationship]

error:

 File "/usr/local/lib/python3.9/site-packages/sqladmin/models.py", line 590, in get_model_attr
assert isinstance(attr, (str, InstrumentedAttribute))
 AssertionError

since what is checked in this assertion is sqlalchemy.orm.RelationshipProperty

I tried to work around that making some patch:

from typing import Union

from sqladmin.models import ModelAdmin
from sqlalchemy.orm import InstrumentedAttribute, RelationshipProperty, ColumnProperty


class ModelAdminWithSQLModelRelationships(ModelAdmin):

    def get_model_attr(
        self, attr: Union[str, InstrumentedAttribute, RelationshipProperty]
    ) -> Union[ColumnProperty, RelationshipProperty]:
        if isinstance(attr, RelationshipProperty):
            return attr

        return super().get_model_attr(attr)

But it didn't work either

File "/usr/local/lib/python3.9/site-packages/sqlalchemy/util/langhelpers.py", line 1214, in _fallback_getattr
  raise AttributeError(key)
AttributeError: key

so I've added some utitlity function to workaround that:

def get_sqlmodel_relationship(model, name):
    rel = model.__sqlmodel_relationships__[name].sa_relationship
    rel.key = name
    return rel


class ModelBAdmin(ModelAdminWithSQLModelRelationships, model=ModelB):
    column_list = [get_sqlmodel_relationship(ModelB, "model_a")]

At this point app could complete startup and I could access admin panel, but when I tried to access list of ModelB objects exception was raised:

sqlalchemy.exc.ArgumentError: Can't find property named "model_a" on mapped class ModelB->modelb in this Query.

so, at this point I gave up, it seems that it would need much more monkeypatching than I anticipated

Steps to reproduce the bug

No response

Expected behavior

Possibility to use SQLModel Relationship in admin panel just like in vanilla SQLAlchemy

Actual behavior

No response

Debugging material

No response

Environment

OS: Manjaro
Python: 3.9.7
SQLAlchemy: 1.4.36

Additional context

No response

@aminalaee aminalaee added the enhancement New feature or request label Jul 15, 2022
@aminalaee
Copy link
Owner

Not sure if I'm missing something but this works fine:

class User(SQLModel, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)
    name: str = Field()
    

class Hero(SQLModel, table=True):
    id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, nullable=False)

    user_id: uuid.UUID = Field(foreign_key="user.id")
    user: User = Relationship(sa_relationship=relationship("User"))


class UserAdmin(ModelAdmin, model=User):
    column_list = [User.name, User.id]

class HerAdmin(ModelAdmin, model=Hero):
    column_list = [Hero.id, Hero.user, Hero.user_id]

@aminalaee
Copy link
Owner

This issue seems to be in SQLModel which doesn't work with SQLAlchemy>=1.4.36. You need to pin that.

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

No branches or pull requests

2 participants