Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django form with many-to-many relationship does not save

I have a custom registration form for my users to add a profile on my app. However, a bug has recently popped up in that the form is not saving the information that is put into all the fields.

My user model, MyUser has a ManyToMany relationship with another model, Interest, and this is where the issues are arising. I am not sure if it is the RegistrationForm or the register view that is causing it, so I have included both below, as well as the model code. I also have a view for the users to update their profile, also included, once it is created, and this is working absolutely perfectly. This is the personal view. As I say, it is only the Interest field that is not being returned, even though it is being filled in on the registration page.

Any help or advice is much appreciated, thanks.

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
like image 474
MrW Avatar asked Jan 21 '15 00:01

MrW


1 Answers

Since you use commit=false for the super(RegistrationForm, self).save call, it doesn't save the many-to-many field. You therefore need to add self.save_m2m() after user.save() in your save() method of RegistrationForm.

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

EDIT: save_m2m() is on the Form, not the Model

like image 181
Daniel Robinson Avatar answered Nov 05 '22 11:11

Daniel Robinson