2011-07-25 144 views
0

我有一個名爲Personnel的模型,我將其用作User模型的模型模型。這裏是我的模型自定義外鍵屬性

class Personnel(models.Model): 
    user = models.OneToOneField(
     User 
    ) 
    phone = models.CharField(
     null=False, max_length=50, verbose_name="Phone" 
    ) 

我需要在ModelForm中使用上述模型。這裏是我的ModelForm

class PersonnelForm(forms.ModelForm): 
    class Meta: 
     model = Personnel 
     exclude = ('user') 

    def __init__(self, *args, **kwargs): 
     personnel = Personnel(user=User.objects.create(username=(''.join(choice(ascii_uppercase + digits) for x in range(30))))) 
     super(PersonnelForm, self).__init__(
      instance=personnel, *args, **kwargs 
     ) 

我不需要的user場從,所以我不包括它顯示在網頁上。但是我仍然需要傳遞一個值,所以通過傳遞一個Personnel實例來啓動我的PersonnelFormUser模式有一個名爲email的字段,應該由用戶輸入,但我不能顯示此字段,因爲它不是我的Personnel模型上的字段。

我可以創建一個名爲email的虛擬域,它在設置時設置user.email域的值,當獲取時,獲取相同的值。事情是這樣:

@property 
def email(): 
    def fget(self): 
     return 'fff' 

    def fset(self, email): 
     self.user.email = email 

我需要將其在類似上面的代碼中的一些方式,因爲I''l可以使用PersonnelFormDjango's generic CRUD views

謝謝。

(請隨意編輯和標題提出一個更好的名字,因此它可能有利於其他人也)


使用丹尼爾的建議是:

class PersonnelForm(forms.ModelForm): 

    email = forms.EmailField(
     required=True, label=_("Email") 
    ) 

    class Meta: 
     model = Personnel 
     exclude = ('user') 

    def save(self, *args, **kwargs): 
     commit = kwargs.get('commit', True) 
     kwargs['commit'] = False 
     personnel = super(PersonnelForm, self).save(*args, **kwargs) 
     if not personnel.user: #To prevent creating a new user when updating. 
      user = User.objects.create_user(
       email=self.cleaned_data['email'], 
       username=(''.join(choice(ascii_uppercase + digits) for x in range(30))), 
      ) 
     if commit: 
      personnel.save() 
     return personnel 

這非常適用於創建一個使用ModelForm的新記錄,但我無法在更新時更新電子郵件或查看電子郵件。

+0

你應該不需要爲用戶傳遞任何值,因爲您已經從PersonnelForm中排除了該屬性。 – Brandon

+0

布蘭登,如果我不排除用戶字段,那麼它會爲我提供一個下拉列表,用於創建「人員」記錄。我需要創建一個'Personnel'記錄並在幕後自動創建一個'User'。每個用戶記錄都有一個隨機的用戶名,密碼是空的,我會在稍後處理它,但是我需要用戶能夠指定電子郵件地址 - 因此屬性會變得混亂。 –

+0

我完全理解。您可以創建User對象並設置任何沒有屬性混亂的屬性。至少有3個地方可以創建User對象 - 在Personnel對象的save方法中,處理Personnel表單的視圖,甚至在Personnel類中附加的post_save信號中。 – Brandon

回答

1

你的問題有兩個誤解。首先,即使你已經排除了它,你仍然需要爲該領域傳遞一個價值;其次,你不能包含不在模型上的字段。這些都不是真的。

絕對有可能定義一個單獨的email字段,將其與實際模型字段一起顯示在表單上,​​然後使用該值創建User對象。

既然你不想修改視圖做這個邏輯(其中IMO是錯誤的決定,但它是你的代碼),你可以在一個覆蓋save方法做到這一點:

class PersonnelForm(forms.ModelForm): 
    email = forms.CharField() 

    class Meta: 
     model = Personnel 
     exclude = ('user',) 

    def save(self, *args, **kwargs): 
     # call super method with commit=False, but remember original commit arg 
     commit = kwargs.get('commit', True) 
     kwargs['commit'] = False 
     new_object = super(PersonnelForm, self).save(*args, **kwargs) 
     user = User.objects.create_user(
      email=self.cleaned_data['user'], 
      username=get_random_username(), 
      password=User.objects.make_random_password() 
     ) 
     new_object.user = user 
     # now save if commit was not explicitly set to False 
     if commit: 
      new_object.save() 
     return new_object 
+0

乾杯丹尼爾。那樣做了。我的印象是,您不能在ModelForm中擁有其他字段,但似乎可以。 –

+0

我遇到了一個小故障。你看,當我創建一個新記錄時,你的方法似乎工作,但是當我使用ModelForm更新記錄時,它會嘗試創建一個新的'User'。爲了解決這個問題,我添加了一個簡單的'if'子句。 (請參閱編輯)。我目前無法解決的另一個問題是如何在更新時顯示'personnel.user.email'字段的值。所有字段都直接從'Personnel'記錄中更新,但'email'在'User'模型中。 –