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

+0

@outis: Он есть: 'user = models.OneToOneField (User)'. Джанго такой волшебный. – mpen

ответ

2

Свойства Python как таковые do not work в моделях django, потому что модели django используют некоторую магию для установки атрибутов экземпляра. Возможно, это имеет эффект.

2

Я не пользователь Django, но я думаю, это потому, что вы не обновили модель после изменения u.email. Попробуйте позвонить u.save() (или каким бы способом этот метод не был вызван), прежде чем обращаться к электронной почте пользователя через профиль.

Вы можете использовать функцию Django signaling для создания обходного пути. В основном, обновление Profile.user когда User посылает 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

Вы вправе угадать, что это 'u.save() ', но это не работает. И независимо, печать 'u.email' без сохранения будет печатать" xxx ". Я думал со свойствами, это будет относиться к той же самой переменной экземпляра? – mpen

+0

'u.profile.user' скорее всего относится к обертке вокруг объекта БД; 'id (u) == id (u.profile.user)' расскажет вам немного больше, так как будет изучать свойства различных объектов. – outis

+0

Ох. Я не знал об этой функции 'id'. Вы правы, они разные. – mpen

Смежные вопросы