How to handle circular imports in SQLAlchemy [duplicate]
Asked Answered
W

1

6

I'm having an issue with circular imports in SQLAlchemy.

I have two files foo.py and bar.py. foo.py defines a SQLAlchemy class Foo, and bar.py defines a class Bar.

Both Foo and Bar are each other's foreign keys, so I map them to each other with Mapped["..."] to get type safety, however that means I need to import the actual classes aswell.

This is causing a circular import error.

What's the best way to handle this issue? What are some general best practices for dealing with circular imports in SQLAlchemy? Can't you have type safety in this case if you use a relationship bidirectionally?

# foo.py

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from .bar import Bar

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar_id = Column(Integer, ForeignKey('bar.id'))
    bar: Mapped["Bar"] = relationship('Bar')

# bar.py

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from .foo import Foo

class Bar(Base):
    __tablename__ = 'bar'
    id = Column(Integer, primary_key=True)
    foo_id = Column(Integer, ForeignKey('foo.id'))
    foo: Mapped["Foo"] = relationship('Foo')

Edit: Note that I can't remove the Bar and Foo imports because then Mapped["..."] will raise an undefined error for "..."

Wield answered 3/4, 2023 at 12:12 Comment(0)
N
8

you can use TYPE_CHECKING. This constant is False at runtime, but True when mypy (and other type-checking tools) evaluate your code

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from .bar import Bar
else:
    Bar = "Bar"

# foo.py

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

class Foo(Base):
    __tablename__ = 'foo'
    id = Column(Integer, primary_key=True)
    bar_id = Column(Integer, ForeignKey('bar.id'))
    bar: Mapped[Bar] = relationship('Bar')
Northwards answered 3/4, 2023 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.