Opened 8 years ago

Last modified 8 years ago

#28210 closed Bug

`<orm_object>._state.adding` behaviour and model inheritance — at Version 6

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 Tim Graham)

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='admin@admin.com')

This will create an Admin instance and User instance, with admin.user_ptr._state.adding == True

  1. 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 (6)

comment:1 by Simon Charette, 8 years ago

This looks similar to #28166 which has been fixed in 1.11.1. Can you confirm it's the case?

comment:2 by Ivaylo Donchev, 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.

Last edited 8 years ago by Ivaylo Donchev (previous) (diff)

comment:3 by Simon Charette, 8 years ago

Component: UncategorizedDatabase layer (models, ORM)
Triage Stage: UnreviewedAccepted
Type: UncategorizedBug

Could you confirm whether or not it's a regression from 1.10? It could be related to 38575b007a722d6af510ea46d46393a4cda9ca29 as well.

in reply to:  3 comment:4 by Ivaylo Donchev, 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 Simon Charette, 8 years ago

Cc: Simon Charette added
Severity: NormalRelease blocker

Tentatively escalating as a release blocker as everything seems to indicate this is a regression.

comment:6 by Tim Graham, 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.

Note: See TracTickets for help on using tickets.
Back to Top