0

我不得不創建一個表單,從一些細節去default.auth.user模型和一些我的自定義模型所以從我這樣做各種渠道搜索後:此方法是否正確使用多個模型創建表單?

Django的版本:1.7

model.py

class UserProfile(models.Model): 
    user = models.OneToOneField(User) 

    title_id = models.ForeignKey('Title') 
    mobile_number = models.CharField(max_length=10) 
    alternate_number = models.CharField(max_length=10) 
    date_of_birth = models.DateField() 
    profession_id = models.ForeignKey('Profession', null=True, blank=True) 
    house_no = models.CharField(max_length=100, blank=True, default='NA') 
    city_id = models.ForeignKey('City', null=True) 
    country_id = models.ForeignKey('Country', null=True) 
    state_id = models.ForeignKey('State', null=True) 
    locality_id = models.ForeignKey('Locality', null=True) 
    profile_picture_path = models.CharField(max_length=100, blank=True, default='NA') 

forms.py:

class UserForm(forms.ModelForm): 
    password = forms.CharField(widget=forms.PasswordInput(attrs={'id': 'password'})) 
    email = forms.CharField(widget=forms.TextInput(attrs={'id': 'email_id'})) 
    username = forms.CharField(widget=forms.TextInput(attrs={'id': 'username'})) 
    first_name = forms.CharField(widget=forms.TextInput(attrs={'id': 'first_name'})) 
    last_name = forms.CharField(widget=forms.TextInput(attrs={'id': 'last_name'})) 

    class Meta: 
     model = User 
     fields = ('email', 'username', 'first_name', 'last_name', 'password') 


class ExtraDetailsForm(UserForm): 
    confirm_password = forms.CharField(widget=forms.PasswordInput(attrs= 
             {'id':'confirm_password'}),max_length=32, 
             required=True,) 
    class Meta: 
     model = UserProfile 
     fields = ('email', 'username', 'title_id', 'first_name', 'last_name', 
        'password', 'confirm_password', 
        'date_of_birth', 'mobile_number',) 

我view.p y是:

def register(request): 
    # A boolean vakue for telling whether the registration was successful 
    registered = False 
    if request.method == 'POST': 
     user_form = UserForm(data=request.POST) 
     additional_details_form = ExtraDetailsForm(data=request.POST) 

     if user_form.is_valid() and additional_details_form.is_valid(): 
      user = user_form.save() 
      user.set_password(user.password) 
      user.save() 

      additional_details = additional_details_form.save(commit=False) 
      additional_details.user = user 
      additional_details.save() 

      registered = True 


     else: 
      print(user_form.errors, additional_details_form.errors) 
    else: 
     user_form = UserForm 
     additional_details_form = ExtraDetailsForm 

    return render(request, 
       'users/register.html', 
     {'user_form' : user_form, 'additional_details_form': additional_details_form, 'registerered': registered}) 

regsiter.html:

{% if registerered %} 
    <p>Thank you for register. check ur email , entered email was</p> 
{% else %} 
    <form action="https://stackoverflow.com/users/register/" method="post">{% csrf_token %} 
     {{ additional_details_form.as_p }} 

     <input type="submit" value="Register" /> 
    </form> 
{% endif %} 

現在的好處是,一切工作正常和細節都被存儲,因爲他們應該。 但不好的是,我不知道這是否是一種正確的方法,因爲我沒有找到任何教程/資源使用這種方法?

回答

1

這是正確的做法,你做得差不多了。只需幾個注意事項:

if user_form.is_valid() and additional_details_form.is_valid(): 

在這一行,如果user_form是無效的,那麼對於additional_details_form驗證將無法運行。要始終驗證它都更改爲:

if all([user_form.is_valid(), additional_details_form.is_valid()]): 

else聲明你的窗體類設置爲*_form變量。它應該是形式的實例,而:

user_form = UserForm() 
additional_details_form = ExtraDetailsForm() 

它可能是一個好主意來包裝你的代碼保存到一個事務:-)

+0

爲什麼你需要驗證兩種形式,即使一個是無效的,如果你只想在兩者都有效時採取行動? – Anentropic

+0

如果這兩個表單都無效,而且只驗證第一個,那麼用戶只會看到第一個表單的錯誤。 – catavaran

+0

啊,好點! – Anentropic

0

好吧,首先ExtraDetailsForm不應UserForm繼承,因爲它們是不同的型號。它應該是這個樣子,而不是:

class UserForm(forms.ModelForm): 
    confirm_password = forms.CharField(widget=forms.PasswordInput(attrs= 
             {'id':'confirm_password'}),max_length=32, 
             required=True,) 

    class Meta: 
     model = User 
     fields = ('email', 'username', 'first_name', 'last_name', 'password', 
        'confirm_password') 


class ExtraDetailsForm(forms.ModelForm): 
    class Meta: 
     model = UserProfile 
     fields = ('title_id', 'date_of_birth', 'mobile_number') 

然後在您的視圖:

from django.contrib.auth import login 
from django.shortcuts import redirect, render 


def register(request): 
    user_form = UserForm(data=request.POST or None) 
    profile_form = ExtraDetailsForm(data=request.POST or None) 

    if all([user_form.is_valid(), profile_form.is_valid()]): 
     user = user_form.save(commit=False) 
     user.set_password(user.password) 
     user.save() 

     profile = profile_form.save() 

     # probably at this point you want to login the new user: 
     login(request, user) 

     # it's good practice to do a redirect here, after a successful 
     # form post, eg to display success page, as this will 
     # prevent accidental re-posting data if user reloads the page 
     return redirect('registration_success') 
    else: 
     print(user_form.errors, profile_form.errors) 

    return render(
     request, 
     'users/register.html', 
     { 
      'user_form' : user_form, 
      'profile_form' : profile_form, 
     } 
    ) 


def registration_success(request): 
    return render('registration_success.html') 

最後,你需要輸出兩種形式的模板:

<form action="https://stackoverflow.com/users/register/" method="post">{% csrf_token %} 
    {{ user_form.as_p }} 
    {{ profile_form.as_p }} 

    <input type="submit" value="Register" /> 
</form> 

和新的模板registration_success.html

<p>Thank you for registering. Check your email, entered email was: {{ request.user.email }}</p> 
+0

它提供了一個錯誤「UserProfile」對象沒有屬性「set_password」,我認爲這是因爲密碼是配置文件模型的一個字段,而不是userProfile型號 – ofnowhere

+0

啊,對不起,我很困惑,因爲'ExtraDetailsForm'繼承'UserForm' ...我沒有注意到它們是針對不同的模型的,這是行不通的......你不能從'ExtraDetailsForm'的'User'模型中訪問字段,我將不得不完全改變我的答案因爲它是有道理的 – Anentropic

0

我建議你在這裏只使用一個包含所有字段的表單。

使用兩種形式沒有任何好處,特別是因爲一種形式會繼承另一種形式,所以當您將POST數據傳遞給每個形式時,這是很奇怪的行爲。

將字段合併到一個表單中,然後重寫表單的「乾淨」方法以檢查兩個密碼字段是否匹配。

您可以創建一個表單將數據保存到一個或多個不同的模型中,這對您的情況尤其有用,因爲您需要一起驗證這些不同模型的數據。

相關問題