代码之家  ›  专栏  ›  技术社区  ›  Somenath Sinha

Django——如何将ForeignKey设置为一个本身与用户有一对一关系的模型?

  •  1
  • Somenath Sinha  · 技术社区  · 4 年前

    这是我的课:

    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}]"
    

    我正在尝试建立这种关系,这样每个用户都有一个 CredsKeychain 这有多个原因 CredKey 物体。我很难引用CredKey的CredsKeychain。我可以通过以下方式直接链接用户:

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

    但这不是我需要的。我实际上需要与CredKeyChain建立ForeignKey关系,该关系与当前用户(在Django admin中提交页面的用户)有一对一的关系。

    当我尝试迁移此模型(在其当前状态下)时,会出现以下错误:

    在不指定默认值的情况下,向credkey添加不可为空的字段“keychain”是不可能的。这是因为数据库需要一些东西来填充现有的行。 请选择修复程序:

    1. 现在提供一个一次性默认值(将在所有现有行上设置此列的空值)
    2. 退出并在模型中手动定义默认值。皮耶。

    我如何引用 user.credskeychain ?


    更新:我已经有了一个信号设置,所以每次创建一个用户时,它都会自动创建一个 CredsKeychain 对于该用户。

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

    更新2:这个模型运行得很好,就像我删除了数据库并删除了旧的迁移(核化了数据库)一样。现在我又开始了,它迁移得很好。那么之前的问题是什么?!

    (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
    
    1 回复  |  直到 4 年前
        1
  •  1
  •   Omid Roshani    4 年前

    如果要向模型中添加任何新字段,请确保数据库中没有任何以前添加的记录。如果您有任何记录,您应该在模型字段中输出一些默认值。因为当您尝试迁移没有任何默认值的新字段时,DB应该做什么?如何填写以前的记录?所以有两种方法可以修复它,正如它所说:

    1. 现在提供一个一次性默认值(将在所有现有行上设置此列的空值)
    2. 退出并在模型中手动定义默认值。皮耶。

    因此,您可以选择选项1并编写python命令来填充以前的记录,或者选择选项2并手动在模型字段中定义默认值