id,summary,reporter,owner,description,type,status,component,version,severity,resolution,keywords,cc,stage,has_patch,needs_docs,needs_tests,needs_better_patch,easy,ui_ux 13987,Primary key not set correctly for concrete->abstract->concrete model inheritance.,Aram Dulyan,nobody,"When a concrete model inherits from an abstract model which in turn inherits from a concrete model, the ""primary_key"" attribute on the {{{OneToOneField}}} in the child model is not set, and the SQL definition for that model does not define a primary key. However, any subsequent children inheriting from the abstract class will have a correctly set primary key. For example: {{{ class ConcreteParent(models.Model): concrete_field = models.TextField() class AbstractParent(ConcreteParent): abstract_field = models.TextField() class Meta: abstract = True class FirstChild(AbstractParent): child_field = models.TextField() class SecondChild(AbstractParent): child_field = models.TextField() }}} The output of ""sqlall"" for these definitions is: {{{ CREATE TABLE ""testapp_concreteparent"" ( ""id"" serial NOT NULL PRIMARY KEY, ""concrete_field"" text NOT NULL ); CREATE TABLE ""testapp_firstchild"" ( ""concreteparent_ptr_id"" integer NOT NULL UNIQUE REFERENCES ""testapp_concreteparent"" (""id"") DEFERRABLE INITIALLY DEFERRED, ""abstract_field"" text NOT NULL, ""child_field"" text NOT NULL ); CREATE TABLE ""testapp_secondchild"" ( ""concreteparent_ptr_id"" integer NOT NULL PRIMARY KEY REFERENCES ""testapp_concreteparent"" (""id"") DEFERRABLE INITIALLY DEFERRED, ""abstract_field"" text NOT NULL, ""child_field"" text NOT NULL ); }}} Note the absence of ""PRIMARY KEY"" in the first child and its presence in the second child. We can also go in the shell to see what's happening: {{{ >>> FirstChild._meta.get_field_by_name('concreteparent_ptr')[0].primary_key False >>> SecondChild._meta.get_field_by_name('concreteparent_ptr')[0].primary_key True >>> FirstChild._meta.get_field_by_name('concreteparent_ptr')[0] == FirstChild._meta.pk True >>> FirstChild._meta.get_field_by_name('concreteparent_ptr')[0] is FirstChild._meta.pk False >>> SecondChild._meta.get_field_by_name('concreteparent_ptr')[0] == SecondChild._meta.pk True >>> SecondChild._meta.get_field_by_name('concreteparent_ptr')[0] is SecondChild._meta.pk True }}} I believe what is happening is that in {{{db.models.options.py}}}, when initialising a Child object in {{{Options._prepare()}}}, the first parent link is selected to be the primary key, its primary key attribute is set to True, and it is then passed to {{{setup_pk()}}}. However, the field fetched through the parent link is the field on the {{{AbstractParent}}} model, and is thus not properly registered with the Child model. But in this process, its primary_key attribute is set to True, which allows the second Child to set it as its PK on the initial {{{add_field()}}} call. The simplest fix for this is to initialise the {{{OneToOneField}}} in {{{ModelBase.__new__()}}} with {{{primary_key=True}}}. Alternately, and perhaps preferably, {{{Options._prepare()}}} can be altered to fetch the {{{OneToOneField}}} for the Child model, rather than the {{{AbstractParent}}} model. I've attached two patches, one for each solution, and perhaps someone more qualified than me can decide which one is the better one.",,closed,"Database layer (models, ORM)",1.2,,fixed,"sprintdec2010, inheritance, abstract, primary key",,Ready for checkin,1,0,0,0,0,0