You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python如何通过类变量获取所属类?微ORM仿SQLAlchemy查询机制疑问

问题解答

核心原理说明

你示例里的A.var是普通字符串实例,Python不会为这类内置类型的值自动存储所属宿主类的引用,因此没有通用内置属性(类似方法的__qualname__)可以直接反向获取到类A。
SQLAlchemy的Column能实现归属识别,核心是它是自定义的描述符类型,会在声明式映射类被定义的阶段,主动将所属类、列名等元信息绑定到Column实例本身。

针对你的ORM实现的改造方案

你现在的Col类直接继承了str,无法存储额外元信息,需要调整实现,同时借助Python的__init_subclass__钩子自动绑定归属信息:

1. 改造Col类

class Col:
    def __init__(self, type_def):
        # 存储列的类型定义,比如INTEGER PRIMARY KEY
        self.type_def = type_def
        # 预留字段:列对应的类属性名,后续自动绑定
        self.name = None
        # 预留字段:列所属的表映射类,后续自动绑定
        self.owner = None
    
    # 保留原字符串拼接行为,方便生成SQL时直接使用
    def __str__(self):
        return f"{self.owner.__tablename__}.{self.name}"

2. 给Base类增加自动绑定逻辑

class Base:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        # 子类定义时自动遍历所有Col属性,绑定归属信息
        for attr_name, attr_val in vars(cls).items():
            if isinstance(attr_val, Col):
                attr_val.name = attr_name
                attr_val.owner = cls

    @classmethod
    def childs(cls):
        subclasses = set()
        work = [cls]
        while work:
            parent = work.pop()
            for child in parent.__subclasses__():
                if child not in subclasses:
                    subclasses.add(child)
                    work.append(child)
        return subclasses

    @classmethod
    def create(cls, cursor):
        query = 'CREATE TABLE IF NOT EXISTS {} ({})'.format(
            cls.__tablename__,
            ', '.join(
                f"{k} {v.type_def}"
                for k, v in vars(cls).items()
                if isinstance(v, Col)
            )
        )
        cursor.execute(query)

    @staticmethod
    def create_all_tables(cursor):
        for cls in __class__.childs():
            cls.create(cursor)

    @classmethod
    def drop(cls, cursor):
        query = 'DROP TABLE IF EXISTS {}'.format(
            cls.__tablename__,
        )
        cursor.execute(query)

    @classmethod
    def insert(cls, cursor, kvRow):
        query = 'INSERT INTO {} ({}) VALUES(:{})'.format(
            cls.__tablename__,
            ', '.join(kvRow.keys()),
            ', :'.join(kvRow.keys())
        )
        cursor.execute(query, kvRow)

3. 效果验证

定义完映射类之后,直接访问列属性就能拿到所属表信息:

class User(Base):
    __tablename__ = 'user'
    id = Col('INTEGER PRIMARY KEY')
    name = Col('VARCHAR')

print(User.id.owner) # 输出<class '__main__.User'>
print(User.id.owner.__tablename__) # 输出'user'
print(User.id.name) # 输出'id'

session.query的实现逻辑

你自己实现query方法时,接收多个Col实例作为参数,每个实例都能通过owner属性拿到对应的映射类,自然就能识别对应的表名,拼接SQL时直接拼接表名.列名即可:

def query(*cols):
    select_part = ', '.join(str(col) for col in cols)
    # 根据列所属的owner去重得到要查询的表列表
    tables = list({col.owner.__tablename__ for col in cols})
    from_part = ', '.join(tables)
    return f"SELECT {select_part} FROM {from_part}"

# 调用示例
print(query(User.id, User.name)) 
# 输出 SELECT user.id, user.name FROM user

内容的提问来源于stack exchange,提问作者rho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 13:57:03