25👍
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.
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.
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.
This is what happens with the OneToOneField
set as primary key:
- Django Admin creates the new
User
instance, with noid
. - Django Admin saves the
User
instance.- Because the
pk
(in this caseid
) is not set, Django attempts to create a new record. - The new record’s
id
is set automatically by the database. - The
post_save
hook creates a newProfile
instance for thatUser
instance.
- Because the
- Django Admin creates the new
Profile
instance, with itsuser
set to the user’sid
. - Django Admin saves the
Profile
instance.- Because the
pk
(in this caseuser
) is already set, Django attempts to fetch an existing record with thatpk
. - Django finds the existing record and updates it.
- Because the
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:
- Django Admin creates the new
User
instance, with noid
. - Django Admin saves the
User
instance, thepost_save
hook creating a newProfile
instance as before. - Django Admin creates the new
Profile
instance, with noid
(the automatically addedpk
field). - Django Admin saves the
Profile
instance.- Because the
pk
(in this caseid
) is not set, Django attempts to create a new record. - The database reports a violation of the table’s uniqueness-constraint on the
user
field. - Django throws an Exception. You will not go to space today.
- Because the
3👍
It seems like setting primary_key=True
on the OneToOneField
connecting the profile model to the User
model fixes this issue. However, I don’t think I understand all the implications of that and why it helps.
I’ll leave this here as a hint, but if that’s the best solution and someone could come up with a well-written explanation, I’d upvote/accept that and possibly delete mine.
- Django Rest Framework won't let me have more than one permission
- Django Filter Model by Dictionary
- Django Admin: has_delete_permission Ignored for "Delete" Action
- Does Django use processes or threads to handle user requests in view?