one to one field related object does not exist

i have created custom user model, and used one to one field for other models, but when i render it as userchangeform for updating user fields in template, it shows me an error ‘related objects does not exist’ for one to one field model

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin




class jobglobeluserManager(BaseUserManager):
    use_in_migrations = True
    username = None

    def create_user(self, email=None, password=None, **extra_fields):
        user = self.model(email=self.normalize_email(email))
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email=None, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)
        extra_fields.setdefault('is_admin', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self.create_user(email, password, **extra_fields)


class jobglobeluser(AbstractBaseUser, PermissionsMixin):
    
    joined_on = models.DateTimeField(auto_now_add=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    useris = models.CharField(max_length=30)
    FirstName = models.CharField(max_length=20)
    LastName = models.CharField(max_length=20)
    email = models.CharField(unique=True, max_length=100)
    code = models.CharField(max_length=20)
    mobile = models.CharField(max_length=13)
    country = models.CharField(max_length=30)
    state = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    Gender = models.CharField(max_length=20)
    password = models.CharField(max_length=20)
    password2 = models.CharField(max_length=20)
    resume = models.FileField(upload_to='docs/')

    objects = jobglobeluserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    

class jobseekerprofile(models.Model):
    
    jobglobeluser = models.OneToOneField(jobglobeluser,on_delete=models.CASCADE,unique=True,null=True,blank=True,auto_created=True)
    profileimg = models.ImageField(default='default.jpg',upload_to='profile_pics')
    age = models.IntegerField(default=False)


class jobseeker_resume_headline_model(models.Model):

    jobglobeluser = models.OneToOneField(jobglobeluser,on_delete=models.CASCADE,unique=True,null=True,blank=True,auto_created=True)
    headline = models.TextField(default='Enter Good Resume Headline Here.',max_length=300)

    
class jobseeker_keyskills_model(models.Model):

    jobglobeluser = models.OneToOneField(jobglobeluser,on_delete=models.CASCADE,unique=True,null=True,blank=True,auto_created=True)
    tags = models.CharField(default='Problemsolving',max_length=1000)

Please show the actual and complete error message you are receiving, along with the view and form that is throwing the error.

Also keep in mind that it’s up to you to create all related objects. The fact that you have defined a OneToOne relationship does not mean those objects are automatically created.

here is forms.py, from where i am rendering form for updaing users, i have not created blank form for fresh updating fields, i am just using direct userchange form bcz i thought it is not necessary to render blank form, and when i click on form for updating fields it shows me an error bcz objects are not created maybe

from django import forms
from django.contrib.auth.forms import UserChangeForm
from .models import *



tags = [('M', 'Male'), ('F', 'Female')]


class jobseeker_keyskills_updateform(UserChangeForm):
    password = None
    jobglobeluser = None
    class Meta:
        model = jobseeker_keyskills_model
        fields = ['tags']


    tags = forms.MultipleChoiceField(choices = tags)


template i have not created yet., but i have created view and urls for it 
here is view
```@login_required(login_url='/userlogin')
def jobseeker_keyskills_update_form_view(request):
    if request.user.useris=='Recruiter':
        return redirect('/recruiter_profile/')
    if request.method == 'POST':
        fm = jobseeker_keyskills_updateform(request.POST,instance=request.user.jobseeker_keyskills_model)
        if fm.is_valid():
            fm.save()
            messages.success(request, 'Updated Successfully.')
        
    else:
        fm = jobseeker_keyskills_updateform(instance=request.user.jobseeker_keyskills_model)
        
    return render(request, 'jobglobel/jobseeker/jobseeker_form_keyskill.html', {'user': request.user, 'form':fm})

The issue with the above code is that request.user does not have a jobseeker_keyskills_model instance. When the ORM attempts to pull that instance from the db using a lookup of user_id = request.user.id it doesn’t find it so it raises an exception.

You have a few options to handle this. 1: you can make sure the row exists before the view runs, 2: make sure the row exists as a part of the view, or 3: handle the possibility that the row doesn’t exist.

  1. Automatically creating jobseeker_keyskills_model in a post_save signal receiver (signals docs)
  2. Changing your view to use get_or_create to ensure that the instance does exist.
  3. Change your view to handle the case of the instance not existing. This would mean you’d need to change the lookup from request.user.jobseeker_keyskills_model to jobseeker_keyskills_model.objects.filter(jobglobeluser=request.user).first() so it can safely return None if it doesn’t exist.

okay thank you so much i understood , i just created signals.py file it solves my problem, but one thing i want to ask you that, in my project i have two user type, and for one user type i want to create that keyskill model(which we are talking about), so is it possible to create model for only one user type, bcz i tried to filter it by usertype in signals.py file , object was not created for another user type so it shown me error for another user type ‘related object does not exist’ for another user type.

That sounds like the same issue as above. The three options I provided should work for that case as well.

thank you this problem hasbeen solved

I have a question related to this subject.

When I defined my models I define the one-to-one relationships as ForeignKeyFields with unique=True.

On saving the model I got the following warning:

System check identified some issues:

WARNINGS:
elements.Hero.node: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
	HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.

I changed the ForeignKey fields to OneToOne fields not knowing that this would result in RelatedObjectDoesNotExist exceptions. In all cases the relation is of type zero or one to one.

Should I change the OneToOneFields to ForeignKeyFields? In that case is there a way to silence the warnings.

Kind regards,

Johanna

I agree with the system-recommendation to prefer the OneToOne field over the foreign key field.

How you resolve the “RelatedObject” exception depends upon the specifics of how you have the field defined and how it’s being used.

Specifically, if you define the OneToOne on the side that always exists, then the field must be defined as null=True to allow for the case where the related object does not exist. If you define the OneToOne on the side that is [0…1], then you don’t need to specify that.

In using that relationship, you do need to be more “explicit” in how you handle the case of a 0 => 1 pairing. You always need to be aware of the possibility of the related object not existing, unlike the case of using the related _set manager in a foreign key where that manager can return a list of 0 items.

That’s what I’ve done:

class Brand(models.Model):
    node = models.OneToOneField(Node, on_delete=models.CASCADE, primary_key=True, related_name='brands', related_query_name='brand')

For all these cases I implemented a FormView which handles the zero or one issue on that side of the relation. Node is never edited in a Class-Based view.

Thanks,

you might rendering form directly via using Userchange form, i was having same issue, if you want to directly use userchange form then you will have to create models objects in signals.py file

Does swapping models.ForeignKey with models.OneToOneField require a database migration update? Best I can tell it does not, but looking to verify that assumption.

When I make the update and run makemigrations it does generate a migration file, however the result seems to do nothing in my database (mysql)

<opinion> I think it needs to - the OneToOneField requires a unique FK to the related model, where a ForeignKey field does not. There should be a constraint that gets added if one doesn’t exist.
</opinion>

I’d be interested in seeing the migration file that was generated.

The mymodel has a

user = ForeignKey(User, unique=True, on_delete=models.CASCADE).

Swapping to:

user = models.OneToOneField(User, on_delete=models.CASCADE)

produces the migration:

class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='mymodel',
            name='user',
            field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
        ),
    ]

What does a sqlmigrate show for this?

TIL of sqlmigrate!

--
-- Alter field user on mymodel
--
ALTER TABLE `myapp_mymodel` DROP FOREIGN KEY `myapp_mymodel_user_id_3f2ed138_fk_auth_user_id`;
ALTER TABLE `myapp_mymodel` ADD CONSTRAINT `myapp_mymodel_user_id_3f2ed138_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);

I suppose this suggests that ForeignKey(..., unique=True...) doesn’t enforce that uniqueness in the database, only in the ORM.

If you set unique=True on a ForeignKey field, makemigrations creates the following warning:

bt.Objectives.user: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.

So no, I wouldn’t draw that conclusion (…only in the ORM) - just the opposite.

1 Like

I think that could be argued to be a bug in the Django migration system. It’s recreating the foreign key constraint when it shouldn’t have to.