2015-11-08 59 views
5

假设虚拟领域我有一个peewee模型看起来或多或少如下:定义在peewee

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

而且我想一个属性添加到模型如下:

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

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

不能做的是以下几点:

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

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

diff好像是一个字段将是非常好的;因此该API的用户不需要知道具体实现是否具有实际字段ab以及实际字段diff,或者实际字段adiff以及实际字段是否为虚拟字段。

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

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

@property 
def seven(self): 
    return 7 

这意味着它不能,在一般情况下,被转换为SQL,而是应该过滤从数据库中检索后的结果。

这可能吗?

更新

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

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

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

回答

4

听起来像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)) 
+0

谢谢!我也接受你的批评......并感谢peewee! – Bach