Save values into another database table with one-to-one relationship in Django during form update

Question:

This is my models.py with 2 tables having a one-to-one table relationship. UserComputedInfo model has a one-to-one relationship with CustomUser model.

from django.contrib.auth.models import AbstractUser
from django.db import models
from django.contrib.auth import get_user_model


class CustomUser(AbstractUser):
    email = models.EmailField(unique=True)
    post_code = models.DecimalField(max_digits=9, decimal_places=6)

    def __str__(self):
        return self.username


class UserComputedInfo(models.Model):
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
    copy_input = models.DecimalField(max_digits=9, decimal_places=6)

    def __str__(self):
        return self.copy_input

Here is the relevant section of my views.py.

from django.shortcuts import redirect
from django.contrib import messages


def profile(request, username):
    if request.method == "POST":
        user = request.user
        form = UserUpdateForm(request.POST, request.FILES, instance=user)
        if form.is_valid():
            user_form = form.save()
            # How to save post_code to copy_input in UserComputedInfo model
            messages.success(request, f'{user_form.username}, Your profile has been updated!')
            return redirect("profile", user_form.username)

    return redirect("homepage")

Here is the relevant section of my forms.py.

from django import forms
from django.contrib.auth import get_user_model


class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()

    class Meta:
        model = get_user_model()
        fields = ['email', 'post_code']

After a user submits a form, profile function will be run and post_code in CustomUser model will be updated. What I want to do is copy the content of post_code to copy_input in UserComputedInfo model as well.

In the template, there is no form input for user_computed_info.copy_input value since the value is the same as custom_user.post_code

How do I do that inside my views.py? I think a good method would be to directly insert the data into the UserComputedInfo model but I don’t know how.

I am running Django v4 and Windows 10.

Asked By: user3848207

||

Answers:

If I understood you well, to cange a variable of another class in the same file it will be like:

#pyfile.py
class test:
    num=1

test().num=2 
print(test().num)

But if you want to change it from a different file, make sure bothe of the files are in the same directory then use:

#pyfile2.py
from pyfile import Test
Test().num=3 
print(Test().num
Answered By: LORD_M.D
if form.is_valid():
        custom_user = form.save(commit=False)
        custom_user.user_computed_info.copy_input = custom_user.post_code
        custom_user.save()
        custom_user.user_computed_info.save() # This may not be necessary but im not 100% sure now. Try without first and if it doesnt save add it on a second try
        messages.success(request, f'{user_form.username}, Your profile has been updated!')
        return redirect("profile", user_form.username)

In this example im assuming that the form otherwise works. If it never worked then you’ll have to double check that the validation checks out. If you don’t know where to look Django will fail form validation silently.

Answered By: Beikeni

Update: This is a flawed answer. For right answer, refer to the one from ThePyGuy

Save values into another database table with one-to-one relationship in Django during form update

I would like to answer my own question.

One way would be to update the UserComputedInfo model directly in views.py.

from django.shortcuts import redirect
from django.contrib import messages
from .models import UserComputedInfo

def profile(request, username):
    if request.method == "POST":
        user = request.user
        form = UserUpdateForm(request.POST, request.FILES, instance=user)
        if form.is_valid():
            user_form = form.save()
            # How to save post_code to copy_input in UserComputedInfo model
            user_computed_info_instance = UserComputedInfo(user_id=user.id)
            user_computed_info_instance.copy_input = 1.18 # or whatever value to be assigned
            user_computed_info_instance.save()

            messages.success(request, f'{user_form.username}, Your profile has been updated!')
            return redirect("profile", user_form.username)

    return redirect("homepage")
Answered By: user3848207

Building on top of your existing answer, the provided answer works for the first time only when user id doesn’t exist, You can use Django’s get_or_create Model method, leaving rest of the logics untouched:

def profile(request, username):
    if request.method == "POST":
        user = request.user
        form = UserUpdateForm(request.POST, request.FILES, instance=user)
        if form.is_valid():
            user_form = form.save()
            # How to save post_code to copy_input in UserComputedInfo model
            user_computed_info_instance, created =UserComputedInfo.objects.get_or_create(user_id=user.id)
            messages.success(request,
                         f'{user_form.username}, Your profile has been updated!')
            user_computed_info_instance.latitude = 1.18 
            user_computed_info_instance.save()

            messages.success(request, f'{user_form.username}, Your profile has been updated!')
            return redirect("profile", user_form.username)

    return redirect("homepage")
Answered By: ThePyGuy