在peewee中定义虚拟字段

时间:2015-11-08 13:47:51

标签: python python-2.7 orm peewee

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

class MyModel(peewee.Model):
    a = peewee.IntegerField()
    b = peewee.IntegerField()

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

    @property
    def diff(self):
        return self.a - self.b

这有时很有帮助;现在,如果ObjectMyModel个实例,我可以使用diff轻松检查其Object.diff

不能做的事情如下:

objects = list(MyModel.select().where(MyModel.diff < 17))

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

diff暴露为一个字段是非常好的。因此,该API的用户无需知道具体实施是将ab作为真实字段,将diff作为虚拟字段,还是a和{ {1}}为真实字段,diff为虚拟字段。

当然,我的真正意图是使用在某些情况下涉及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)

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

这可能吗?

更新

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

例如,我的@property def seven(self): return 7 方法可以成为diff,并按预期工作。我的hybrid_property不能成为一个,或者至少看起来像它;其开头的complicated_property条件将不断返回ifTrue,并且不会充当函数。

Peewee可能还有更多魔法隐藏在那里;我会继续寻找并报告我的发现。

1 个答案:

答案 0 :(得分:5)

hybrid_property之类的声音将是您正在寻找的内容。这是the hybrid methods documentation

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

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

@radius.expression
def radius(cls):
    return fn.ABS(cls.length) / 2

因此,您可以看到同一属性的两个函数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))