Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django – How to set ForeignKey to a model that itself has a one-to-one relationship to User?

Here’s my class:

from django.db import models
from django.contrib.auth.models import User


class CredsKeychain(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    
    def __str__(self) -> str:
        return f"{self.user.username}'s credentials"


class CredKey(models.Model):
    keychain = models.ForeignKey(CredsKeychain, on_delete=models.CASCADE)
    tag = models.CharField(max_length=100)
    username = models.CharField(max_length=100)
    enc_password = models.CharField(max_length=100)
    last_used_successfully = models.DateTimeField(default=None)
    
    def __str__(self) -> str:
        return f"{self.keychain.user.username}'s credentials for {self.tag} [{self.username}]"

I’m trying to have the relationship set up such that each user has a CredsKeychain that has multiple CredKey objects. I’m having a hard time trying to reference CredsKeychain from CredKey. I can directly link the user, via:

keychain = models.ForeignKey(User, on_delete=models.CASCADE)

But that’s not what I need. I actually need to have a ForeignKey relationship to the CredsKeychain that has a one-to-one relationship with the current user (who submits the page in Django admin).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

When I try to migrate this model (in its current state), I get the error:

It is impossible to add a non-nullable field ‘keychain’ to credkey without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:

  1. Provide a one-off default now (will be set on all existing rows with a null value for this column)
  2. Quit and manually define a default value in models.py.

How can I reference the user.credskeychain?


Update: I already have a signal setup so that everytime a user is created, it automatically creates a CredsKeychain for that user.

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

Update 2: Model works just fine as-is once I dropped the DB and deleted the old migrations (nuked the DB). Now that I start again, it migrates just fine. So what was the problem earlier?!

(env) PS C:\Users\somsinha\scripts\djpu-keystore> python manage.py makemigrations
Migrations for 'keystore':
  keystore\migrations\0001_initial.py
    - Create model CredsKeychain
    - Create model CredKey
(env) PS C:\Users\somsinha\scripts\djpu-keystore> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, keystore, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying keystore.0001_initial... OK
  Applying sessions.0001_initial... OK

>Solution :

if you want to add any new fields to your models make sure that you don’t have any previously added records in the DB. if you have any records you should out some default values in the model field. because when you try to migrate new fields without any default value what should DB do ? how should it fill for the previous records? so there is 2 way to fix it as it says:

  1. Provide a one-off default now (will be set on all existing rows with a null value for this column)
  2. Quit and manually define a default value in models.py.

so you can select option 1 and write a python command to fill the previous records or select option 2 and define the default value in the model field manually

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading