#28210 closed Bug (fixed)
`<orm_object>._state.adding` behaviour and model inheritance
Reported by: | Ivaylo Donchev | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.11 |
Severity: | Release blocker | Keywords: | |
Cc: | Simon Charette | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Let's say we have the following models:
class User(models.Model): email = models.CharField(max_length=255, unique=True) password = models.CharField(max_length=32) class Admin(User): pass class ThirdPartyUser(User): pass
Steps to reproduce:
admin = Admin.objects.create(email='admin@admin.com')
This will create an Admin instance and User instance, with admin.user_ptr._state.adding == True
ThirdPartyUser.objects.create(user_ptr = admin.user_ptr)
This will raise the following error {'email': ['User with this Email address already exists.'], 'id': ['User with this ID already exists.'] }
When the admin is created, the admin.user_ptr._state.adding
is True, but admin._state.adding is False (as it is already created).
If we set admin.user_ptr._state.adding = False
, step 2 is passing without errors.
Change History (11)
comment:1 by , 8 years ago
comment:2 by , 8 years ago
Yeah, but it's not about the _state.db.Basically, if we have these two models:
class Parent(models.Model): pass class ChildA(Parent): pass class ChildB(Parent): pass
and we create "ChildA" object with obj = ChildA.objects.create(), we'll have 2 new instances - *(ChildA) obj* and *(Parent) obj.parent_ptr)*. Now, if you try to create "ChildB" instance as follows:
parent = obj.parent_ptr # parent._state.adding == True child_b = ChildB(parent_ptr=obj.parent_ptr) child_b.__dict__.update(parent) # to set all required attributes (if any) child_b.full_clean() # this will throw an error for all of the unique fields of the parent instance ("id"for example) child_b.save()
So, if you set obj.parent_ptr._state.adding = False
as soon as obj is created, the code above is working without errors.
Basically, the problem is that if we don't modify the _state's adding, it's no possible to create a new instance with the same parent_ptr.
follow-up: 4 comment:3 by , 8 years ago
Component: | Uncategorized → Database layer (models, ORM) |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → Bug |
Could you confirm whether or not it's a regression from 1.10? It could be related to 38575b007a722d6af510ea46d46393a4cda9ca29 as well.
comment:4 by , 8 years ago
Well, I hit this bug while upgrading Django from 1.10 to 1.11.1, but I didn't reproduce all the corner cases in the Django1.10.
Replying to Simon Charette:
Could you confirm whether or not it's a regression from 1.10? It could be related to 38575b007a722d6af510ea46d46393a4cda9ca29 as well.
comment:5 by , 8 years ago
Cc: | added |
---|---|
Severity: | Normal → Release blocker |
Tentatively escalating as a release blocker as everything seems to indicate this is a regression.
comment:6 by , 8 years ago
Description: | modified (diff) |
---|
I can't reproduce using the steps described in the description. How does ThirdPartyUser.objects.create()
raise a dictionary? Please clarify.
comment:7 by , 8 years ago
Tim, I think the reporter was referring to form validation generating a form.errors
along the dict he provided.
Unique field validation relies on the _state.adding
flag to determine whether or not it should run.
An appropriate test in this case would be along the lines of
child = Child.objects.create() self.assertFalse(child.parent_ptr._state.adding)
comment:9 by , 8 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
This looks similar to #28166 which has been fixed in 1.11.1. Can you confirm it's the case?