我有两个相关模型:
class FirstModel(models.Model):
base_value = models.FloatField()
class SecondModel(models.Model):
parent = models.ForeignKey(FirstModel)
@property
def parent_value(self):
return self.parent.base_value
@property
def calculate(self):
return self.parent_value + 1
一般来说,SecondModel.calculate
主要在其相关的 FirstModel
上下文中使用。但是,我有时希望能够使用临时值作为其 parent_value
来调用 calculate
。像这样的事情:
foo = SecondModel()
# would look in the database for the related FirstModel and add 1 to its base_value
foo.calculate
foo.parent_value = 10
foo.calculate # should return 11
显然您不能执行此操作,因为 parent_value
是只读属性。我还有许多类似于 SecondModel 的不同模型需要具备这种功能。
我考虑并尝试了几件事,但似乎没有一个完全有效:
1) 编写 Django 代理模型 - 可能,但对象的数量相当多,所以我会编写很多类似的代码。此外,似乎存在与覆盖属性相关的错误:https://code.djangoproject.com/ticket/16176 。但它看起来像这样:
class ModelProxy(SecondModel):
class Meta:
proxy = True
def __init__(self, temp_value):
self.parent_value = temp_value
2) 重载实例上的 parent_value
属性 - 像这样:
foo = SecondModel()
setattr(foo, 'parent_value', 10)
但是你不能这样做,因为属性是类的成员,而不是实例的成员。我只想为实例设置临时值
3) 元类还是类生成器? - 看起来过于复杂。另外,我不确定如果我使用元类动态生成 models.Model 子级的类会发生什么。我会遇到数据库表不同步的问题吗?
4) 使用适当的 getter 和 setter 重写属性? - 也许解决方案是重写 SecondModel 以便可以设置属性?
有什么建议吗?
最佳答案
我相信 mixin 可以实现您想要做的事情,并提供一种简单且可重用的方式来支持计算中的临时值。通过将以下示例混合到您想要此行为的每个模型中,您可以:
- 为每个模型设置临时父值
- 调用calculate时,会检查是否有可用的属性parent_value,如果没有,则在计算中使用临时父值。
下面的代码应该可以实现您正在寻找的内容 - 抱歉,我还无法测试它,但它应该是正确的 - 如果有任何问题需要编辑,请告诉我。
class CalculateMixin(object):
@property
def temp_parent_value(self):
return self._temp_parent_value
@temp_parent_value.setter
def temp_parent_value(self, value):
self._temp_parent_value = value
@property
def calculate(self):
parent_value = self.parent_value if self.parent_value else self.temp_parent_value
return parent_value + 1
class SecondModel(models.Model, CalculateMixin):
parent = models.ForeignKey(FirstModel)
self.temp_parent_value = 'Whatever value you desire'
@property
def parent_value(self):
return self.parent.base_value
关于Python/Django - Django 模型的动态属性重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17293908/