pythonsqlalchemy

Why am I getting "NameError: Module 'dashboard_permission' has no mapped classes registered under the name '_sa_instance_state'"?


Problem

I have a database with tables named qs_dashboard and profile which are linked with an intermediate table named dashboard_permissions. My issue is that when I try to add a relationship in my SQLAlchemy models from Dashboard to Profile via dashboard_permissions.profile_id, I get the following error whether or not my code is testing the new relationship:

NameError: Module 'qs_dashboard_permission' has no mapped classes registered under the name '_sa_instance_state'

I have no idea what _sa_instance_state refers to. The stack trace points to the first time that a query is evaluated. Ex:

query = select(Profile).filter(Profile.uuid == 'some uuid')
profile: Profile = session.scalars(query).first()

The relevant parts of my schema are as follows:

Attempted Solutions

Model files:

dashboard.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from .profile import Profile
    from .dashboard_permission import DashboardPermissions
else:
    Profile = 'Profile'
    DashboardPermissions = 'DashboardPermissions'

from . import Base

from sqlalchemy import (
    String,
)
from sqlalchemy.orm import (
    mapped_column,
    relationship,
    Mapped,
    DynamicMapped,
)

class Dashboard(Base):
    __tablename__ = 'dashboard'

    id: Mapped[str] = mapped_column(String, primary_key = True)

    profiles: DynamicMapped[Profile] = relationship(Profile,
        lazy = 'dynamic',
        secondary = 'dashboard_permission',
        foreign_keys = 'DashboardPermissions.profile_id',
        #overlaps = 'qs_dashboard_permissions',
        #back_populates = 'dashboards',
    )

profile.py

from sqlalchemy import Integer
from sqlalchemy.orm import (
    mapped_column,
    Mapped,
)

class Profile(Base):
    __tablename__ = 'profile'

    id: Mapped[Integer] = mapped_column(Integer, primary_key = True, index = True, unique = True)

dashboard_permissions.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from .profile import Profile
    from .dashboard import Dashboard
else:
    Profile = 'Profile'
    Dashboard = 'Dashboard'

from . import Base

from sqlalchemy import (
    ForeignKey,
    Integer,
    String,
)
from sqlalchemy.orm import (
    relationship,
    mapped_column,
    Mapped,
)

from sqlalchemy import (
    DateTime,
)

from .enums.qs_permission import QsPermission

import boto3

cognito = boto3.client('cognito-idp')

class DashboardPermissions(Base):
    __tablename__ = 'dashboard_permissions'

    profile_id: Mapped[int] = mapped_column(Integer, ForeignKey('profile.id'), primary_key = True)
    profile: Mapped[Profile] = relationship(Profile, foreign_keys = [profile_id], back_populates = 'dashboard_permissions', overlaps='dashboard_permissions')

    dashboard_id: Mapped[str] = mapped_column(String, ForeignKey('dashboard.id'), primary_key = True)
    dashboard: Mapped[Dashboard] = relationship(Dashboard, foreign_keys = [dashboard_id], overlaps='dashboard_permissions')

    shared_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('profile.id'))
    shared_by: Mapped[Profile] = relationship(Profile, foreign_keys = [shared_by_id], back_populates = 'dashboard_permissions_shared', overlaps='dashboard_permissions')

Solution

  • My issue was that I had a typo in the secondary table name. In this example, "dashboard_permission" should have been "dashboard_permissions".