在 vanilla SQLAlchemy 中创建关系

Creating Relationships in vanilla SQLAlchemy

我最近开始将 SQLAlchemy 用于我正在处理的数据库应用程序。事情进展顺利,直到我需要关系。我查看了文档并找出了该怎么做。但是,它仅在我的模型位于同一个 .py 文件中时才有效。这对我来说有点混乱,所以我试图将它们分离到它们自己的 model_name.py 文件中。例如:

frame_model.py:

from __future__ import annotations

from .db_connector import master_session, db_engine
from sqlalchemy import Column, String, Integer, Date, Computed, ForeignKey, cast, Index
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import TSVECTOR
from sqlalchemy.types import TypeDecorator
from datetime import datetime

# Create ts_vector type.
class TSVector(TypeDecorator):
    impl = TSVECTOR
    cache_ok = True


base = declarative_base()


class FrameModel(base):
    __tablename__ = "inventory"

    frame_id: int = Column(Integer, primary_key=True, autoincrement=True)
    frame_name: str = Column(String(140), nullable=False)
    quantity: int = Column(Integer, nullable=False)
    frame_size: str = Column(String(45), nullable=False)
    colour: str = Column(String(100), nullable=False)
    price: int = Column(Integer, nullable=False)
    frame_category: str = Column(
        String(100),
        ForeignKey("categories.category", ondelete="CASCADE"),
        nullable=False,
    )
    date_entered: Date = Column(
        Date, default=datetime.today().strftime("%Y-%m-%d"), nullable=False
    )
    frame_code: str = Column(String(50), nullable=False)
    __ts_vector__ = Column(
        TSVector(),
        Computed(
            "to_tsvector('english', frame_name || ' ' || frame_size || ' ' || colour || ' ' || frame_category || ' ' || frame_code )",
            persisted=True,
        ),
    )

    sale = relationship("SaleModel")

    __table_args__ = (Index("idx_frame_fts", __ts_vector__, postgresql_using="gin"),)

    def __repr__(self) -> str:
        return f"<{self.__class__.__name__}: {self.frame_name}, Category: {self.frame_category}>"

    def save_to_db(self):
        master_session.add(self)
        master_session.commit()

    def delete_from_db(self):
        master_session.delete(self)
        master_session.commit()

base.metadata.create_all(db_engine)

sale_model.py:

from __future__ import annotations

from sqlalchemy.orm import relationship

from .db_connector import db_engine, master_session

from sqlalchemy import (
    Column,
    String,
    Integer,
    Date,
    UniqueConstraint,
    ForeignKey,
    Computed,
    cast,
    Index,
    UniqueConstraint,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import TSVECTOR
from sqlalchemy.types import TypeDecorator
from datetime import datetime


class TSVector(TypeDecorator):
    impl = TSVECTOR
    cache_ok = True


base = declarative_base()


class SaleModel(base):
    __tablename__ = "sales"

    order_id = Column(Integer, primary_key=True, autoincrement=True)
    frame = Column(String(100), nullable=False)
    quantity_sold = Column(Integer, nullable=False)
    customer = Column(String(200), nullable=False)
    receipt_num = Column(String(50), nullable=False)
    frame_id = Column(Integer, ForeignKey("inventory.frame_id", ondelete="SET NULL"))
    frame_code = Column(String(50), nullable=False)
    item_price = Column(Integer, nullable=False)
    category = Column(String(100), nullable=False)
    colour = Column(String(100), nullable=False)
    size = Column(String(45), nullable=False)
    date_sold = Column(
        Date, default=datetime.today().strftime("%Y-%m-%d"), nullable=False
    )
    __ts_vector__ = Column(
        TSVector(),
        Computed(
            "to_tsvector('english', frame || ' ' || frame_code || ' ' || receipt_num || ' ' || customer)",
            persisted=True,
        ),
    )

    frame = relationship("FrameModel")

    __table_args__ = (
        Index("sale_idx", __ts_vector__, postgresql_using="gin"),
        UniqueConstraint("receipt_num", name="_receipt_num_uc"),
    )

    def __repr__(self) -> str:
        return f"<Receipt number: {self.receipt_num}, customer: {self.customer}, frame: {self.frame}>"

    # Add and update the sale
    def save_to_db(self):
        master_session.add(self)
        master_session.commit()

    # Delete the sale
    def delete_from_db(self):
        master_session.delete(self)
        master_session.commit()

base.metadata.create_all(db_engine)

但这一直给我错误:


sqlalchemy.exc.NoReferencedTableError: 找不到与列 'sales.frame_id' 相关联的外键 table 'inventory' 用于生成目标列 'frame_id'[ 的外键=12=]


我尝试了所有方法,从将父项 class 导入子项 class 并在父项 class 中创建引用子项的关系(sale = relationship("sale" , backref="inventory) 但到目前为止没有任何效果。任何指导将不胜感激。

注意:.py 文件位于名为“models”的文件夹中,该文件夹本身有一个空白的 init.py 文件。

多亏了@snakecharmerb 的建议和一些额外的工作,我才能够解决这个问题。

在 sale_model.py 中,我导入了 FrameModel class 并添加了行:

frame = relationship("FrameModel", back_populates="sale")