2010-02-08 71 views
1

真的很困惑这里发生了什么。我有一个类定义如下:Python属性:两个变量的实例?

class Profile(models.Model): 
    user = models.OneToOneField(User) 
    primary_phone = models.CharField(max_length=20) 
    address = models.ForeignKey(Address) 

    @property 
    def primary_email(self): return self.user.email 
    @primary_email.setter 
    def primary_email(self, val): self.user.email = val 

NB:user具有属性email

从命令行

现在,我想这样的:

>>> u = User.objects.get(pk=1) 
>>> u.email = 'xxx' 
>>> u.profile.primary_email 
u'yyy' 

它吐出了一个不同的价值?具体来说,旧的的值为u.email。这是怎么回事?这怎么可能?我基本上只想为email创建一个别名。


一些更多的信息:

>>> id(u) == id(u.profile.user) 
False 
>>> u 
<User: mark> 
>>> u.profile.user 
<User: mark> 

他们似乎是user不同的副本,但他们......什么?两者都以相同的值开始?

这样做似乎提交更改:

>>> u.profile.primary_email = 'yyy' 
>>> u.profile.user.save() 

u.save()不会因为u != u.profile.user无论出于何种原因做的伎俩。我想这回答我的问题,但它仍然有些跛脚。

这是可能这两个指的是Python中的同一个对象,对吗?在Django中这只是一个有趣的设计决定造成了这个问题?

+0

创建User.profile的代码在哪里? 'id(u)== id(u.profile.user)'? – outis 2010-02-08 00:48:04

+0

@outis:它在那里:'user = models.OneToOneField(User)'。 Django就像那样神奇。 – mpen 2010-02-08 02:56:42

回答

2

django模型中的Python属性本身do not work,因为django的模型在设置实例属性方面做了一些神奇的工作。也许这是有影响的。

2

我不是Django的用户,但我猜这是因为在更改u.email后没有更新模型。在通过配置文件访问用户的电子邮件之前,请尝试拨打u.save()(或任何方法被调用的方法)。

您可以使用Django的signaling功能构建解决方法。基本上,更新Profile.userUser发送post_save

# models.py 
... 
def update_user(**kwargs): 
    kwargs['instance'].profile.user = kwargs['instance'] 

models.signals.post_save.connect(update_user, sender=User) 

你仍然需要调用User.save这个工作,并重挫Profile.user可能有其他的副作用。可能有更多的Django-y方式;有更多的Django经验比我可能发布的人更多。例如,可能会将首次访问User.profile并将Profile.user设置为父级用户的代码挂钩,而不是创建新的User

或者,无论何时通过Users.objects.get和参考Users.profile获得用户,请将用户对象替换为User.profile中的用户属性。

+0

你猜对了,你是对的。save()',但这不起作用。不管如何,不用保存打印'u.email'就会打印出“xxx”。我认为与属性,它会指的是完全相同的实例变量? – mpen 2010-02-08 02:55:33

+0

'u.profile.user'很可能是指数据库对象的包装器; 'id(u)== id(u.profile.user)'会告诉你更多,同样会检查各种对象的属性。 – outis 2010-02-08 03:45:59

+0

哦。我不知道这个'id'函数。你说得对,他们不一样。 – mpen 2010-02-08 08:49:19