gpt4 book ai didi

python - 在 Django 中使用 InlineAdmin 和 post_save 信号创建配置文件模型

转载 作者:太空狗 更新时间:2023-10-29 17:55:32 25 4
gpt4 key购买 nike

我按照 Extending the existing user model 中的描述创建了一个“个人资料”模型(与用户模型具有一对一的关系) .配置文件模型与另一个模型具有可选的多对一关系:

class Profile(models.Model):
user = models.OneToOneField(User, primary_key=True)
account = models.ForeignKey(Account, blank=True, null=True, on_delete=models.SET_NULL)

如那里所述,我还创建了一个内联管理员:

class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
verbose_name_plural = 'profiles'
# UserAdmin and unregister()/register() calls omitted, they are straight copies from the Django docs

现在,如果我在创建用户时没有在管理中选择account,则不会创建配置文件模型。所以我connectpost_save信号,再次遵循文档:

@receiver(post_save, sender=User)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()

只要我在管理员中选择一个帐户,这就可以正常工作,但如果我这样做,我会得到一个IntegrityError 异常,告诉我 重复的键值违反了唯一约束“app_profile_user_id_key”详细信息:键 (user_id)=(15) 已经存在。

显然,内联管理员试图自己创建 profile 实例,但我的 post_save 信号处理程序当时已经创建了它。

如何解决此问题,同时满足以下所有要求?

  1. 无论新用户是如何创建的,之后总会有一个 profile 模型链接到它。
  2. 如果用户在创建用户的过程中在管理中选择了一个account,这个account 将被设置到新的profile 模型中。如果不是,则该字段为 null。

环境:Django 1.5,Python 2.7

相关问题:

最佳答案

这个问题可以通过在 OneToOneField 上设置 primary_key=True 来避免,指向 User 模型,正如你自己发现的那样。

这个工作的原因似乎很简单。

当您尝试创建一个模型实例并在保存之前手动设置pk 时,Django 将尝试在数据库中查找具有该pk 的记录并更新它而不是盲目地尝试创建一个新的。如果不存在,它会按预期创建新记录。

当您将 OneToOneField 设置为主键并且 Django 管理员将该字段设置为相关的 User 模型的 ID 时,这意味着 pk已经设置,Django 将首先尝试查找现有记录。

这是将 OneToOneField 设置为主键时发生的情况:

  1. Django 管理员创建新的 User 实例,没有 id
  2. Django 管理员保存 User 实例。
    1. 因为 pk(在本例中为 id)未设置,Django 尝试创建新记录。
    2. 新记录的id由数据库自动设置。
    3. post_save Hook 为该 User 实例创建一个新的 Profile 实例。
  3. Django 管理员创建新的 Profile 实例,并将其 user 设置为用户的 id
  4. Django 管理员保存 Profile 实例。
    1. 因为 pk(在本例中为 user)已经设置,Django 尝试使用该 pk 获取现有记录。<
    2. Django 找到现有记录并更新它。

如果您没有显式设置主键,Django 会添加一个使用数据库的auto_increment 功能的字段:数据库将pk 设置为下一个最大值那不存在。这意味着该字段实际上将留空,除非您手动设置它,因此 Django 将始终尝试插入新记录,从而导致与 OneToOneField 上的唯一性约束发生冲突。

这是导致原始问题的原因:

  1. Django 管理员创建新的 User 实例,没有 id
  2. Django Admin 保存 User 实例,post_save 钩子(Hook)像以前一样创建一个新的 Profile 实例。
  3. Django 管理员创建新的 Profile 实例,没有 id(自动添加的 pk 字段)。
  4. Django 管理员保存 Profile 实例。
    1. 因为 pk(在本例中为 id)未设置,Django 尝试创建新记录。
    2. 数据库报告 user 字段违反了表的唯一性约束。
    3. Django 抛出异常。你今天不会去太空。

关于python - 在 Django 中使用 InlineAdmin 和 post_save 信号创建配置文件模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14345303/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com