Relationships#

GraphQL DB seamlessly handles SQLAlchemy relationships in GraphQL queries.

One-to-Many#

Define relationships in your models:

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

class User(ModelBase):
    __tablename__ = 'users'

    name: Mapped[str]
    posts = relationship("Post", back_populates="author")

class Post(ModelBase):
    __tablename__ = 'posts'

    title: Mapped[str]
    author_id: Mapped[uuid.UUID] = mapped_column(ForeignKey('users.id'))
    author = relationship("User", back_populates="posts")

Query relationships:

query {
  users {
    name
    posts {
      title
    }
  }
}

Many-to-Many#

Use association tables:

from sqlalchemy import Table, Column

user_roles = Table(
    'user_roles',
    ModelBase.metadata,
    Column('user_id', UUID, ForeignKey('users.id')),
    Column('role_id', UUID, ForeignKey('roles.id'))
)

class User(ModelBase):
    __tablename__ = 'users'

    name: Mapped[str]
    roles = relationship("Role", secondary=user_roles, back_populates="users")

class Role(ModelBase):
    __tablename__ = 'roles'

    name: Mapped[str]
    users = relationship("User", secondary=user_roles, back_populates="roles")

Eager Loading#

Prevent N+1 queries with eager loading:

from sqlalchemy.orm import selectinload

@api.field
def users_with_posts(self) -> list[User]:
    """Get users with posts eagerly loaded."""
    return User.query().options(selectinload(User.posts)).all()

@api.field
def posts_with_authors(self) -> list[Post]:
    """Get posts with authors eagerly loaded."""
    return Post.query().options(selectinload(Post.author)).all()

Learn more in the Performance guide.