在peewee中定义虚拟字段

Bac*_*ach 6 python orm python-2.7 peewee

假设我有一个peewee模型,看起来或多或少如下:

class MyModel(peewee.Model):
    a = peewee.IntegerField()
    b = peewee.IntegerField()
Run Code Online (Sandbox Code Playgroud)

我希望为该模型添加一个属性,如下所示:

    @property
    def diff(self):
        return self.a - self.b
Run Code Online (Sandbox Code Playgroud)

这有时很有帮助; 现在,如果Object是一个MyModel例子,我可以很容易地检查其diffObject.diff.

不能做的是以下内容:

objects = list(MyModel.select().where(MyModel.diff < 17))
Run Code Online (Sandbox Code Playgroud)

这是因为MyModel.diff是一个简单的属性,可能总是大于17.它不是一个ExpressionMyModel.a < 17.

暴露diff就好像它是一个领域一样非常好; 让API的用户不需要知道具体的实现是否有ab作为实际领域,diff作为一个虚拟的,或者说adiff作为真正的领域和b作为一个虚拟的.

当然,我的真正意图是使用在某些情况下涉及更复杂的计算的属性diff; 一个例子是

@property
def complicated_property(self):
    if 17 <= self.a <= 173:
        return a_complicated_math_function(self.a + self.b)
    return another_complicated_math_function(self.a * self.b ** 2)
Run Code Online (Sandbox Code Playgroud)

另一方面,它可以是一个非常简单的属性,例如

@property
def seven(self):
    return 7
Run Code Online (Sandbox Code Playgroud)

这意味着它通常不能转换为SQL,而应该在从数据库中检索结果后过滤结果.

那可能吗?

更新

我刚刚发现了peewee playhouse的混合方法/属性.这些为我的问题提供了部分解决方案.

例如,我的diff方法可以成为一个hybrid_property,并按预期工作.我complicated_property不能成为一个,或者至少看起来像它; if它开始时的条件将返回TrueFalse不断返回,并且不会作为一个函数.

Peewee可能还有一些神奇的藏身之处; 我会继续寻找并报告我的发现.

col*_*fer 5

听起来就像hybrid_property你要找的那样.这是混合方法文档

至于你的更新,如果你刚刚在文档中进一步阅读...

@hybrid_property
def radius(self):
    return abs(self.length) / 2

@radius.expression
def radius(cls):
    return fn.ABS(cls.length) / 2
Run Code Online (Sandbox Code Playgroud)

所以你看到同一属性的两个函数,radius.在模型实例上调用时,将调用第一个函数.在查询中调用时的第二个.

你可以写:

@hybrid_property
def complicated_property(self):
    if 17 <= self.a <= 173:
        return a_complicated_math_function(self.a + self.b)
    return another_complicated_math_function(self.a * self.b ** 2)

@complicated_property.expression
def complicated_property(cls):
    # Here you will need to use a CASE statement most likely.
    # If you want to turn it into SQL, you obviously need to know
    # what SQL you want to turn it into...
    return case(
        None,
        (cls.a.between(17, 173), fn.math(fn.more_math(cls.a, 1.23))),
        default=fn.another_complicated_math(cls.a))
Run Code Online (Sandbox Code Playgroud)