这种方法对于使用多个模型创建表单是否正确?

时间:2015-01-12 20:11:23

标签: django django-models django-forms django-templates django-views

我必须创建一个表单,其中一些细节转到 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.py是:

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="/users/register/" method="post">{% csrf_token %}
        {{ additional_details_form.as_p }}

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

现在好处是一切都运转良好,细节正在按照应有的方式存储。 但不好的是我不知道这是否是一种正确的方法,因为我没有找到使用这种方法的任何教程/资源?

3 个答案:

答案 0 :(得分: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()

将保存代码包装到一个事务中可能是个好主意: - )

答案 1 :(得分: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="/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>

答案 2 :(得分:0)

我建议你只使用一个包含所有字段的表单。

使用两个表单没有任何好处,特别是因为一个表单继承了另一个表单,当你将POST数据传递给每个表单时,这是奇怪的行为。

将字段合并为一个表单,然后覆盖&#39; clean&#39;表单的方法,以检查两个密码字段是否匹配。

您可以创建单个表单以将数据保存到一个或多个不同的模型中,这在您的情况下尤其有用,因为您需要同时验证这些不同模型的数据。