假设我有一个看起来或多或少的peewee模型如下:
class MyModel(peewee.Model):
a = peewee.IntegerField()
b = peewee.IntegerField()
我希望为该模型添加一个属性,如下所示:
@property
def diff(self):
return self.a - self.b
这有时很有帮助;现在,如果Object
是MyModel
个实例,我可以使用diff
轻松检查其Object.diff
。
我不能做的事情如下:
objects = list(MyModel.select().where(MyModel.diff < 17))
这是因为MyModel.diff是一个简单的属性,可能总是大于17.它不是Expression
MyModel.a < 17
。
将diff
暴露为一个字段是非常好的。因此,该API的用户无需知道具体实施是将a
和b
作为真实字段,将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
条件将不断返回if
或True
,并且不会充当函数。
Peewee可能还有更多魔法隐藏在那里;我会继续寻找并报告我的发现。
答案 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))