我的设置大致如下:
# account/models.py
Account(models.Model):
""" The user profile """
user = models.OneToOneField("auth.User", primary_key=True, related_name="account")
balance = models.DecimalField(max_digits=32, decimal_places=2, default=0)
activation_key = models.CharField(max_length=32)
...
我有一个看起来像这样的信号处理程序:
def recalculate_credit(sender, instance=None, created=None, **kwargs):
print(instance.user.account.activation_key)
account = instance.user.get_profile()
print(account.activation_key)
account.calculate_balance()
account.save()
我在那里添加了打印语句以突出显示问题。在我的注册过程中,我设置了activation_key
属性,保存,然后稍后触发此信号。第一个print语句返回该激活键,第二个返回''
。
这怎么可能?我错过了.get_profile()
的工作原理吗?上面的代码实际上是从用户帐户中删除activation_key
值。是否有一些延迟加载,或者我不知道的对象缓存?
答案 0 :(得分:3)
是的,所以这里发生的是django每次都不会从DB重新加载.account
attr或.get_profile()
的值,它在第一次访问后被缓存。要修复,当您需要保证对象是新鲜的,或者只通过 访问相关的Account.objects.get(id=user.account_id)
对象时,要么使用Account
从数据库获取一个全新的副本.get_profile()
API或.account
相关描述符 - 不是两者。只要您以与调用.save()
之前相同的方式访问对象,就不会出现此问题。
从概念上讲,潜在的问题是Django没有进行任何身份映射 - Foo.objects.get(id=1)
,运行两次,会在内存中产生两个独立的Foo
个对象。它们的属性不会被共享,更新一个不会改变另一个。将它们从数据库中恢复时,该模型的DB行看起来是什么样的“快照”更合适。要查明数据库值现在,您必须再次运行查询。