具有多对多关系的Django表单不保存

Posted

技术标签:

【中文标题】具有多对多关系的Django表单不保存【英文标题】:Django form with many-to-many relationship does not save 【发布时间】:2015-03-19 09:35:19 【问题描述】:

我有一个自定义注册表单,供我的用户在我的应用上添加个人资料。但是,最近出现了一个错误,即表单没有保存放入所有字段的信息。

我的用户模型MyUser 与另一个模型Interest 具有多对多关系,这就是问题所在。我不确定是RegistrationForm 还是register 视图导致了它,所以我在下面包含了两者以及模型代码。 我也有一个视图让用户更新他们的个人资料,也包括在内,一旦创建,这绝对是完美的。这是personal 视图。 正如我所说,只有Interest 字段没有被返回,即使它正在注册页面上填写。

非常感谢任何帮助或建议,谢谢。

models.py

class Interest(models.Model):
    title = models.TextField()

    def __unicode__(self):
        return self.title

class MyUser(AbstractBaseUser):
    email = models.EmailField(
                        verbose_name='email address',
                        max_length=255,
                        unique=True,
                    )
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    date_of_birth = models.DateField()
    course = models.ForeignKey(Course, null=True)
    location = models.ForeignKey(Location, null=True)
    interests = models.ManyToManyField(Interest, null=True)
    bio = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

views.py

def register(request):
    if request.method == 'POST':
        form = RegistrationForm(data=request.POST)
        if form.is_valid():
            form.save()
            return redirect('/friends/home/')
    else:
        form = RegistrationForm()

    template = "adduser.html"
    data =  'form': form, 
    return render_to_response(template, data, context_instance=RequestContext(request))

@login_required(login_url='/friends/login/')
def personal(request):
    """
    Personal data of the user profile
    """
    profile = request.user

    if request.method == "POST":
        form = ProfileForm(request.POST, instance=profile)
        if form.is_valid():
            form.save()
            messages.add_message(request, messages.INFO, _("Your profile information has been updated successfully."))
            return redirect('/friends/success/')
    else:
        form = ProfileForm(instance=profile)

    template = "update_profile.html"
    data =  'section': 'personal', 'form': form, 
    return render_to_response(template, data, context_instance=RequestContext(request))

forms.py

class RegistrationForm(forms.ModelForm):
    """
    Form for registering a new account.
    """
    email = forms.EmailField(widget=forms.TextInput, label="Email")
    password1 = forms.CharField(widget=forms.PasswordInput,
                                label="Password")
    password2 = forms.CharField(widget=forms.PasswordInput,
                                label="Password (again)")
    course = forms.ModelChoiceField(queryset=Course.objects.order_by('title'))
    location = forms.ModelChoiceField(queryset=Location.objects.order_by('location'))

    class Meta:
        model = MyUser
        fields = [
            'first_name',
            'last_name',
            'date_of_birth',
            'email',
            'password1',
            'password2',
            'course',
            'location',
            'interests',
            'bio',
            ]

    def __init__(self, *args, **kwargs):#Sort interests alphabetically
        super(RegistrationForm, self).__init__(*args, **kwargs)
        self.fields['interests'].queryset = Interest.objects.order_by('title')

    def clean(self):
        cleaned_data = super(RegistrationForm, self).clean()
        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
            if self.cleaned_data['password1'] != self.cleaned_data['password2']:
                raise forms.ValidationError("Passwords don't match. Please enter again.")
        return self.cleaned_data

    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        user.set_password(self.cleaned_data['password1'])
        if commit:
            user.save()
        return user

【问题讨论】:

【参考方案1】:

由于您将commit=false 用于super(RegistrationForm, self).save 调用,因此它不会保存多对多字段。因此,您需要在RegistrationFormsave() 方法中的user.save() 之后添加self.save_m2m()

见https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method

编辑:save_m2m() 在表单上,​​而不是模型上

【讨论】:

save_m2m() is on the Form :)

以上是关于具有多对多关系的Django表单不保存的主要内容,如果未能解决你的问题,请参考以下文章

在多对多关系对象django的对象中获取null

通过 Django 中的模型表单保存多对多数据

如何解决具有多对多关系的石墨烯 django 节点字段

Django - 使用表单集在不通过表的情况下建立 2 个模型之间的多对多关系

django 管理表单上的大型多对多关系

Django 模型 - 至少多对多之一