pythonsqlalchemyflask-sqlalchemy

How to elegantly combine complex Python object and SQLAlchemy object model classes?


I have a rather complex class with complex properties computed from a provided df to init and these properties may be other class types that can be eventually serialized into a string. In Python I want to deal with objects rather than primitive types but also want to use SQLAlchemy for interacting with databases. The columns in the table are the same as many of the class properties, how can I combine these two classes elegantly? I could use composition and have the db model as an object within the class, but that doesn't feel like truly combining? I'd have to have two separate classes that call each other's APIs.

Subclassing wouldn't work I don't think as the column properties cannot have the same name as the column. When I use the ORM and pull from the db, I'd like the object to be already initialized so I can modify the df and change the properties, but init isn't called using the ORM.

from enum import Enum

import pandas as pd
from sqlalchemy import Base, Float, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class Thing(Enum):
    A = "a"
    B = "b"


def thing_factory(df: pd.DataFrame) -> Thing:
    tmp = df["thing"].max()
    return Thing.A if tmp > 4 else Thing.B


class ComplexObject:
    def __init__(self, df: pd.DataFrame):
        self.df = df
        self.thing: Thing = thing_factory(self.df)

    @property
    def complex_property(self) -> float:
        # complex logic here
        return 0


class Base(DeclarativeBase):
    pass


class ComplexObjectModel(Base):
    __tablename__ = "complex_object"

    id: Mapped[int] = mapped_column(primary_key=True)
    thing: Mapped[str] = mapped_column(Text)
    complex_property: Mapped[float] = mapped_column(Float)

Solution

  • use __abstract__ in class in order to achieve the behavior im looking for

    https://docs.sqlalchemy.org/en/20/orm/declarative_config.html#abstract