gpt4 book ai didi

django - 访问外键时使用代理模型

转载 作者:行者123 更新时间:2023-12-01 06:36:04 27 4
gpt4 key购买 nike

我有两个相关的 Django 模型。其中一个模型在其 __init__ 中进行了昂贵的计算。如果没有 Not Acceptable 成本/风险,我无法搬到其他地方。

事实证明,并非在所有情况下都需要这些昂贵的计算,因此我引入了一个代理模型来绕过它们。但是,它们经常被需要,因此将昂贵的用于代理是不切实际的。

所以,我的代码基本上是这样的:

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 开始实例并访问相关 person每个 PersonFact .这段代码不需要真正昂贵的人员计算,这些昂贵的计算对性能的影响是 Not Acceptable 。所以我希望能够实例化 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 的内部知道只与数据库列交互一次。

最佳答案

到目前为止,我想出的最佳解决方案是在相关模型的 __init__ 上做一些可怕的事情。 :

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")

def __init__(self, *args, **kw):
models.Model.__init__(self, *args, **kw)
index = None
for i, field in enumerate(self._meta.local_fields):
if field.name == 'lightweight_person':
index = i
break
if index is not None:
self._meta.local_fields.pop(index)

这显然向对象管理器隐藏了该字段的存在以进行更新和插入,因此不会发生“多次指定列”错误;当我选择现有数据时,该字段仍然会填充。

这似乎有效,但它非常可怕——我不知道它是否会对我的代码的其他部分产生副作用。

关于django - 访问外键时使用代理模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14822743/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com