如 扩展现有用户模型.配置文件模型与另一个模型具有可选的多对一关系:
I created a 'profile' model (with a 1-to-1 relationship to the User model) as described on Extending the existing user model. The profile model has an optional many-to-one relationship to another 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)
正如那里记录的那样,我还创建了一个内联管理员:
As documented there, I also created an inline admin:
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
,则不会创建配置文件模型.所以我 连接到 post_save 信号,再次遵循文档:
Now if I don't select an account
in the admin when creating the user, the profile model won't be created. So I connect to the post_save signal, again just following the documentation:
@receiver(post_save, sender=User)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
只要我在管理员中不选择一个 account
就可以正常工作,但如果我这样做了,我会得到一个 IntegrityError
异常,告诉我 duplicate key value 违反了唯一约束app_profile_user_id_key" DETAIL: Key (user_id)=(15) already exists.
This works fine as long as I do not select an account
in the admin, but if I do, I'll get an IntegrityError
exception, telling me that duplicate key value violates unique constraint "app_profile_user_id_key" DETAIL: Key (user_id)=(15) already exists.
显然,内联管理员尝试自己创建 profile
实例,但我的 post_save
信号处理程序当时已经创建了它.
Apparently, the inline admin tries to creates the profile
instance itself, but my post_save
signal handler has already created it at that time.
如何解决这个问题,同时满足以下所有要求?
How do I fix this problem, while keeping all of the following requirements?
profile
模型链接到它.account
,那么这个account
将会在之后被设置在新的profile
模型上.如果不是,则该字段为 null.
profile
model linking to it as well afterwards.account
in the admin during user creation, this account
will be set on the new profile
model afterwards. If not, the field is null.
环境:Django 1.5、Python 2.7
Environment: Django 1.5, Python 2.7
相关问题:
可以通过在 OneToOneField
上设置 primary_key=True
指向 用户
模型,正如你自己想出来的那样.
The problem can be avoided by setting primary_key=True
on the OneToOneField
pointing at the User
model, as you have figured out yourself.
这行得通的原因似乎很简单.
The reason that this works seems to be rather simple.
当您尝试创建模型实例并在保存之前手动设置 pk
时,Django 将尝试使用该 pk
在数据库中查找记录并更新它而不是盲目地尝试创建一个新的.如果不存在,它会按预期创建新记录.
When you try to create a model instance and set the pk
manually before saving it, Django will try to find a record in the database with that pk
and update it rather than blindly attempting to create a new one. If none exists, it creates the new record as expected.
当您将 OneToOneField
设置为主键并且 Django 管理员将该字段设置为相关 User
模型的 ID 时,这意味着 pk
已设置,Django 将首先尝试查找现有记录.
When you set the OneToOneField
as the primary key and Django Admin sets that field to the related User
model's ID, that means the pk
is already set and Django will attempt to find an existing record first.
这是将 OneToOneField
设置为主键时发生的情况:
This is what happens with the OneToOneField
set as primary key:
User
实例,没有 id
.User
实例.User
instance, with no id
.User
instance.
pk
(本例中为 id
)未设置,Django 尝试创建新记录.id
由数据库自动设置.post_save
挂钩为该 User
实例创建一个新的 Profile
实例.pk
(in this case id
) is not set, Django attempts to create a new record.id
is set automatically by the database.post_save
hook creates a new Profile
instance for that User
instance.Profile
实例,并将其 user
设置为用户的 id
.Profile
实例.
Profile
instance, with its user
set to the user's id
.Profile
instance.
pk
(在本例中为 user
)已设置,Django 尝试使用该 pk
获取现有记录.李>pk
(in this case user
) is already set, Django attempts to fetch an existing record with that pk
.如果你没有显式设置主键,Django 会添加一个使用数据库的 auto_increment
功能的字段:数据库将 pk
设置为下一个最大值那不存在.这意味着该字段实际上将留空,除非您手动设置它,因此 Django 将始终尝试插入新记录,从而导致与 OneToOneField
上的唯一性约束冲突.
If you don't set the primary key explicitly, Django instead adds a field that uses the database's auto_increment
functionality: the database sets the pk
to the next largest value that doesn't exist. This means the field will actually be left blank unless you set it manually and Django will therefore always attempt to insert a new record, resulting in a conflict with the uniqueness-constraint on the OneToOneField
.
这是导致原始问题的原因:
This is what causes the original problem:
User
实例,没有 id
.User
实例,post_save
钩子像以前一样创建一个新的 Profile
实例.Profile
实例,没有 id
(自动添加的 pk
字段).Profile
实例.User
instance, with no id
.User
instance, the post_save
hook creating a new Profile
instance as before.Profile
instance, with no id
(the automatically added pk
field).Profile
instance.
pk
(本例中为 id
)未设置,Django 尝试创建新记录.user
字段中违反了表的唯一性约束.pk
(in this case id
) is not set, Django attempts to create a new record.user
field.这篇关于在 Django 中使用 InlineAdmin 和 post_save 信号创建配置文件模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!