2010-02-08 103 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