【发布时间】:2013-02-11 23:16:34
【问题描述】:
我有两个相关的 Django 模型。其中一个模型在其__init__ 中进行了昂贵的计算,如果没有不可接受的成本/风险,我无法将其转移到其他地方。
事实证明,并非在所有情况下都需要这些昂贵的计算,因此我引入了一个绕过它们的代理模型。但是,它们经常需要,因此将昂贵的用于代理是不切实际的。
所以,我的代码基本上是这样的:
class Person(models.Model):
def __init__(self, *args, **kw):
models.Model.__init__(self, *args, **kw)
do_some_really_expensive_things()
class LightweightPerson(Person):
class Meta:
proxy = True
def __init__(self, *args, **kw):
models.Model.__init__(self, *args, **kw)
class PersonFact(models.Model):
fact = models.TextField()
person = models.ForeignKey(Person)
这很好用——我的大部分代码查询都是在 Person 上的。并且在代码不需要真正昂贵的东西的少数地方,它改为查询LightweightPerson,并且性能更好。
但是,我的一些代码从PersonFact 实例开始,并为每个PersonFact 访问相关的person。此代码不需要真正昂贵的人员计算,并且这些昂贵计算对性能的影响是不可接受的。所以我希望能够在这种情况下实例化 LightweightPerson 而不是 Person。
我想出的方法是添加第二个 ForeignKey 引用代理类,并使用相同的数据库列:
class PersonFact(models.Model):
fact = models.TextField()
person = models.ForeignKey(Person, db_column="person_id")
lightweight_person = models.ForeignKey(
LightweightPerson, db_column="person_id",
related_name="lightweight_personfact_set")
所以现在当我需要提升性能时,我的代码可以执行以下操作:
facts = PersonFact.objects.select_related(
"lightweight_person").all()
for fact in facts:
do_something_with(fact.lightweight_person)
这很好用!直到我尝试保存一个新的PersonFact:
>>> fact = PersonFact(fact="I like cheese", person=some_guy_i_know)
>>> fact.save()
Traceback (most recent call last):
...
DatabaseError: column "person_id" specified more than once
:-(
有什么方法可以做到这一点,而无需对当前位于 Person.__init__ 中的代码进行可怕的重构?理想情况下,我可以在我的调用代码中发出信号“当现在访问person_fact.person 时,请实例化LightweightPerson 而不是Person”。或者,或者,我希望能够在 PersonFact 上声明一个“代理相关字段”,它会隐藏相同的数据库列,但 Django 的内部知道只与数据库列交互一次。
【问题讨论】:
-
我在 IRC 的#django 中进行了类似的讨论,基本上他们告诉我我在做什么被认为是一个错误。有时这是唯一可行的解决方案,这有点令人沮丧。
标签: django django-models