class Admin(User):
pass
class ThirdPartyUser(User):
pass
}}}
Steps to reproduce:
1. {{{ admin = Admin.objects.create(email='ad...@admin.com') }}}
This will create an Admin instance and User instance, with
`admin.user_ptr._state.adding == True`
2. {{{ 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.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by Simon Charette):
This looks similar to #28166 which has been fixed in 1.11.1. Can you
confirm it's the case?
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:1>
Comment (by Ivaylo Donchev):
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.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:2>
* component: Uncategorized => Database layer (models, ORM)
* type: Uncategorized => Bug
* stage: Unreviewed => Accepted
Comment:
Could you confirm whether or not it's a regression from 1.10? It could be
related to 38575b007a722d6af510ea46d46393a4cda9ca29 as well.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:3>
Comment (by Ivaylo Donchev):
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 [comment:3 Simon Charette]:
> Could you confirm whether or not it's a regression from 1.10? It could
be related to 38575b007a722d6af510ea46d46393a4cda9ca29 as well.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:4>
* cc: Simon Charette (added)
* severity: Normal => Release blocker
Comment:
Tentatively escalating as a release blocker as everything seems to
indicate this is a regression.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:5>
Old description:
> 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,
> widget=forms.PasswordInput)
>
> class Admin(User):
> pass
>
> class ThirdPartyUser(User):
> pass
> }}}
>
> Steps to reproduce:
> 1. {{{ admin = Admin.objects.create(email='ad...@admin.com') }}}
>
> This will create an Admin instance and User instance, with
> `admin.user_ptr._state.adding == True`
>
> 2. {{{ 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.
New description:
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:
1. {{{ admin = Admin.objects.create(email='ad...@admin.com') }}}
This will create an Admin instance and User instance, with
`admin.user_ptr._state.adding == True`
2. {{{ 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.
--
Comment (by Tim Graham):
I can't reproduce using the steps described in the description. How does
`ThirdPartyUser.objects.create()` raise a dictionary? Please clarify.
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:6>
Comment (by Simon Charette):
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
[https://github.com/django/django/blob/master/django/db/models/base.py#L1013
whether or not it should run].
An appropriate test in this case would be along the lines of
{{{#!python
child = Child.objects.create()
self.assertFalse(child.parent_ptr._state.adding)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:7>
* has_patch: 0 => 1
Comment:
[https://github.com/django/django/pull/8519 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:8>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:9>
* status: new => closed
* resolution: => fixed
Comment:
In [changeset:"59ab1b2683b6c090dc409d9eb8303aadbd590c04" 59ab1b26]:
{{{
#!CommitTicketReference repository=""
revision="59ab1b2683b6c090dc409d9eb8303aadbd590c04"
Fixed #28210 -- Fixed Model._state.adding on MTI parent model after saving
child model.
Regression in 38575b007a722d6af510ea46d46393a4cda9ca29.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:10>
Comment (by Tim Graham <timograham@…>):
In [changeset:"f2b8fa1763116a9b8fbe7791a4b009c95cf8c0b1" f2b8fa17]:
{{{
#!CommitTicketReference repository=""
revision="f2b8fa1763116a9b8fbe7791a4b009c95cf8c0b1"
[1.11.x] Fixed #28210 -- Fixed Model._state.adding on MTI parent model
after saving child model.
Regression in 38575b007a722d6af510ea46d46393a4cda9ca29.
Backport of 59ab1b2683b6c090dc409d9eb8303aadbd590c04 from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/28210#comment:11>