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

如何在自定义ORM中实现类似SQLAlchemy/Peewee的where表达式传递?

实现ORM中表达式参数的核心原理

你疑惑的核心点是ORM的关键技巧:Python确实会先计算表达式,但这些表达式返回的不是布尔值,而是承载了逻辑的表达式对象。下面拆解具体实现步骤:

1. 自定义字段类:重载魔法方法

ORM里的Person.name不是普通字符串,是自定义字段类(比如Field)的实例。我们需要重载__eq__、__lt__、__or__这类魔法方法,让它们返回一个表达式节点,而非直接计算布尔结果。

示例代码:

class Field:
    def __init__(self, db_column):
        self.db_column = db_column  # 对应数据库表的列名

    # 重载相等运算符
    def __eq__(self, value):
        return BinaryExpression(left=self, op="=", right=value)
    
    # 重载小于运算符
    def __lt__(self, value):
        return BinaryExpression(left=self, op="<", right=value)
    
    # 重载大于运算符
    def __gt__(self, value):
        return BinaryExpression(left=self, op=">", right=value)

2. 表达式对象:构建逻辑树

定义BinaryExpression类存储二元表达式的结构(左操作数、运算符、右操作数),同时重载位运算(|、&)支持多表达式组合:

class BinaryExpression:
    def __init__(self, left, op, right):
        self.left = left
        self.op = op
        self.right = right

    # 重载或运算符,组合表达式
    def __or__(self, other):
        return BinaryExpression(left=self, op="OR", right=other)
    
    # 重载与运算符
    def __and__(self, other):
        return BinaryExpression(left=self, op="AND", right=other)

    # 生成SQL片段的核心方法
    def to_sql(self):
        # 递归处理嵌套表达式
        if isinstance(self.left, BinaryExpression):
            left_sql = self.left.to_sql()
        elif isinstance(self.left, Field):
            left_sql = self.left.db_column
        else:
            # 处理普通值,比如字符串加引号
            left_sql = f"'{self.left}'"

        if isinstance(self.right, BinaryExpression):
            right_sql = self.right.to_sql()
        elif isinstance(self.right, Field):
            right_sql = self.right.db_column
        else:
            right_sql = f"'{self.right}'"

        return f"({left_sql} {self.op} {right_sql})"

3. Query类:接收并处理表达式

where方法不需要"获取表达式本身",它接收的就是上面生成的BinaryExpression对象,调用to_sql()就能转换成SQL片段:

class Query:
    def __init__(self, model_cls):
        self.model_cls = model_cls
        self.where_expr = None

    def where(self, *expressions):
        # 多表达式默认用AND连接
        if len(expressions) > 1:
            combined = expressions[0]
            for expr in expressions[1:]:
                combined = combined & expr
            self.where_expr = combined
        else:
            self.where_expr = expressions[0]
        return self  # 支持链式调用

    def to_sql(self):
        table_name = self.model_cls.__name__
        sql = f"SELECT * FROM {table_name}"
        if self.where_expr:
            sql += f" WHERE {self.where_expr.to_sql()}"
        return sql

4. 模型类:整合字段与查询

定义基础Model类,让业务模型继承它:

class Model:
    @classmethod
    def select(cls):
        return Query(cls)

# 业务模型示例
class Person(Model):
    name = Field("name")
    birthday = Field("birthday")

测试验证

现在可以模拟ORM的用法:

d1940 = "1940-01-01"
d1960 = "1960-01-01"

# 简单表达式查询
grandma_query = Person.select().where(Person.name == 'Grandma L.')
print(grandma_query.to_sql())
# 输出: SELECT * FROM Person WHERE (name = 'Grandma L.')

# 复杂组合表达式
range_query = Person.select().where((Person.birthday < d1940) | (Person.birthday > d1960))
print(range_query.to_sql())
# 输出: SELECT * FROM Person WHERE ((birthday < '1940-01-01') OR (birthday > '1960-01-01'))

核心总结

  • 所有比较/逻辑运算都返回表达式对象,而非布尔值,这是ORM能捕获逻辑的关键
  • 表达式对象可以嵌套组合,形成一棵抽象语法树
  • where方法只需要接收这些对象,调用其to_sql方法即可生成对应的SQL片段

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:45:08