最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to support SQLAlchemy and SQLModel at the same time in FastAPI - Stack Overflow

programmeradmin1浏览0评论

We are migrating a big application from Flask to FastAPI. Currently sqlalchemy is used for the database models. In the future we probably want to switch to sqlmodel but in order to keep migrating effort to a minimum we want to support both at the same time.

I managed to somewhat support both at the same time but updating my alembic configuration but the issue is that relationships are not working. I can only use SQLModel and SQLAlchemy if they do not share any relationships right now which is effectively useless for me.

This is my current file structure:

.
└── models/
    ├── __init__.py  --> Define declarative base object 'Base' for SQLAlchemy tables
    ├── users.py  --> SQLAlchemy table
    ├── books.py  --> SQLAlchemy table
    ├── tags.py  --> SQLAlchemy table
    ├── books_tags.py  --> Many-2-Many association table between 'books' and 'tags'
    └── stats.py  --> SQLModel table

This is working due to the fact that the stats table does not have any relationships with the other tables.

However I want to change the books table from sqlalchemy to sqlmodel while keeping the relationships intact .

My .models/__init__.py file:

from sqlalchemy.orm import declarative_base
from sqlalchemy import MetaData

# Create a common MetaData object
common_metadata = MetaData()

# Use the common MetaData object for SQLAlchemy Base
Base = declarative_base(metadata=common_metadata)

from .users import User
from .books import Book
from .tags import Tag

The books table with sqlalchemy looks like this:

from sqlalchemy import Column, String, Integer, Date, DateTime, ForeignKey
from sqlalchemy.dialects.postgresql import UUID as pgUUID
from sqlalchemy.orm import relationship
from datetime import datetime
import uuid as uid
from . import Base
from .books_tags import book_tag_association  # many-to-many association table


class Book(Base):
    __tablename__ = "books"
    uuid = Column(pgUUID(as_uuid=True), primary_key=True, default=uid.uuid4, nullable=False)
    title = Column(String, nullable=False)
    author = Column(String, nullable=False)
    publisher = Column(String, nullable=False)
    published_date = Column(Date, nullable=False)
    page_count = Column(Integer, nullable=False)
    language = Column(String, nullable=False)
    user_uuid = Column(pgUUID(as_uuid=True), ForeignKey("users.uuid"), nullable=True)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    user = relationship("User", back_populates="books", lazy="selectin")
    tags = relationship("Tag", secondary=book_tag_association, back_populates="books", lazy="selectin")

The 'User' table is basically the same, for reference here is also the book_tag_association table:

from sqlalchemy import Table, Column, ForeignKey
from sqlalchemy.dialects.postgresql import UUID as pgUUID
from models import Base 

# Association table for many-to-many relationship
book_tag_association = Table(
    'book_tag_association', Base.metadata,
    Column('book_uuid', pgUUID(as_uuid=True), ForeignKey('books.uuid', ondelete='CASCADE'), primary_key=True),
    Column('tag_uuid', pgUUID(as_uuid=True), ForeignKey('tags.uuid', ondelete='CASCADE'), primary_key=True)
)

Up to this point everything is working just fine. But if I want to change the books table from sqlalchemy to sqlmodel like this the relationships won't work:

from sqlmodel import SQLModel, Field, Column, Relationship
from datetime import datetime, date
from typing import Optional, TYPE_CHECKING
import sqlalchemy.dialects.postgresql as pg
import uuid as uid

if TYPE_CHECKING:  # This is needed to prevent circular imports
    from .users import User


class Book(SQLModel, table=True):
    __tablename__ = "books"
    uuid: uid.UUID = Field(
        sa_column=Column(pg.UUID, nullable=False,
                         primary_key=True, default=uid.uuid4)
    )
    title: str
    author: str
    publisher: str
    published_date: date
    page_count: int
    language: str
    user_uuid: Optional[uid.UUID] = Field(
        default=None, foreign_key="users.uuid")
    created_at: datetime = Field(sa_column=Column(
        pg.TIMESTAMP, default=datetime.now))
    update_at: datetime = Field(sa_column=Column(
        pg.TIMESTAMP, default=datetime.now))
    user: Optional["User"] = Relationship(
        back_populates="book", sa_relationship_kwargs={"lazy": "selectin"})
    tags: List["Tag"] = Relationship(back_populates="books", link_model=book_tag_association)

The main issue is that my book_tag_association table is not able to resolve books.uuid. The main problem in my opinion is that the SQLModel tables are not part of the declarative base object Base. Therefore all the relationships between sqlalchemy and sqlmodel can not be resolved.

How can I make sure that the SQLModel tables are "known" within the declarative Base in order to use relationships with each other?

发布评论

评论列表(0)

  1. 暂无评论