Search code examples
djangodjango-modelsdjango-views

Data not being saved to the Profile model


When attempting to register a new user through the registration form, the phone number (phone_number) and library ID (library_id) fields are not being saved to the database. Despite these fields being included in the registration form and rendered correctly, the submitted values are not written the database.

views.py

def user_register(request):
    userIsAuthenticated = False
    if request.user.is_authenticated:
        username1 = request.user.username
        userIsAuthenticated = True
    else:
        username1 = "N/A"
        userIsAuthenticated = False

    if request.method == 'GET':
            form = RegisterForm()
            return render(request, "register.html", {"form":form, "username": username1, "userIsAuthenticated": userIsAuthenticated})
    
    if request.method == 'POST':
        form = RegisterForm(request.POST) 
        if form.is_valid():
            user = form.save(commit=False)
            user.save()
            login(request, user)
            return render(request, "register-success.html")
        else:
            return render(request, 'register.html', {"form":form, "username": username1, "userIsAuthenticated": userIsAuthenticated})

forms.py

class RegisterForm(UserCreationForm):
    first_name = forms.CharField(max_length=100)
    last_name = forms.CharField(max_length=100)
    library_id = forms.CharField(max_length=100)
    phone_number = forms.CharField(max_length=100)

    class Meta:
        model = User
        fields = ['first_name', 'last_name', 'username', 'email', 'password1', 'password2']

    def save(self, commit=True):
        user = super().save(commit=False)
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.email = self.cleaned_data['email']
        if commit:
            Profile.objects.create(
                user=user,
                phone_number=self.cleaned_data['phone_number'],
                library_id=self.cleaned_data['library_id']
            )
            user.save()
        return user

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    phone_number = models.CharField(max_length=100)
    library_id = models.CharField(max_length=100)

    def __str__(self):
        return self.user.username

signals.py

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

More details (registration process, the problem in better detail):

  1. fill out the registration form Register form on the website
  2. let's take a look at the db table
id username first_name last_name email
27 dolor Lorem ipsum sit@amet.consectetur

The rest of the details are saved in the Profile model. Let's look at it!

id user_id phone_number library_id
12 27 "" ""

Here, the data from the form we filled out are not saved.

Additionaly, I am able to fill out those fields (phone_number, library_id) using the admin panel, so the problem is most likely in the user_register function.


Solution

  • It's because the logic where you save that information on the Profile model is contingent on commit=True in your form's .save() method.

    But you never call RegisterForm.save(commit=True), you only ever call it with commit=False. That means the Profile-logic is never executed. The reason you get a Profile object in the database at all, is due to the create_user_profile-signal.

        def save(self, commit=True):
            user = super().save(commit=False)
            user.first_name = self.cleaned_data['first_name']
            user.last_name = self.cleaned_data['last_name']
            user.email = self.cleaned_data['email']
            if commit:     # <---- NB! Conditional execution only when commit=True
                Profile.objects.create(
                    user=user,
                    phone_number=self.cleaned_data['phone_number'],
                    library_id=self.cleaned_data['library_id']
                )
                user.save()
            return user
    
    def user_register(request):
        [...]
    
        if request.method == 'POST':
            form = RegisterForm(request.POST) 
            if form.is_valid():
                user = form.save(commit=False)  # <-- NB! commit=False
    

    There's a lot of ways you can do this, but you're gonna have to decide on how to handle the save-logic between your form and your model(s).