[Django] #20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns

21 views
Skip to first unread message

Django

unread,
Jul 19, 2013, 1:49:14 PM7/19/13
to django-...@googlegroups.com
#20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns
-------------------------------+------------------------------------
Reporter: dowstreet@… | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 1.5
Severity: Normal | Keywords: Muti-table Inheritance
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+------------------------------------
There seems to be a problem with queries that (i) span several levels of
multi-table inheritance subclassing when (ii) PKs do not match all the way
up the hierarchy. This situation can arise when a higher level object
(e.g. parent) is created before a lower level object (e.g. grandchild).
The query seems to use the PK of the grandchild's parent instead of
walking the whole way up the hierarchy when looking up fields that are
stored in the grandparent table.

In the example below there are three levels in the class hierarchy. When
accessing the name field (which is stored in the Level1 base class) from
an object in Level3, the query returns an unexpected value 'Top 1' instead
of the expected 'Bot 1':

{{{

# models.py

from django.db import models

class Level1(models.Model):
""" Top level base class """

level1_id = models.AutoField(primary_key=True, db_column='Level1_ID')
name = models.CharField(max_length=32, db_column='Name', blank=True,
null=True)

class Meta:
db_table = 'Level1'


class Level2(Level1):
""" Middle level class """

level2_id = models.AutoField(primary_key=True, db_column='Level2_ID')
level1 = models.OneToOneField('Level1', db_column='Level1_ID',
parent_link=True) # parent class

class Meta:
db_table = 'Level2'


class Level3(Level2):
""" Bottom level class """

level3_id = models.AutoField(primary_key=True, db_column='Level3_ID')
level2 = models.OneToOneField('Level2', db_column='Level2_ID',
parent_link=True) # parent class

class Meta:
db_table = 'Level3'

}}}

Using the shell to add a Level1 object and then a Level3 object to an
otherwise empty database:

{{{

from sc_test.models import *

>>> top1 = Level1()
>>> top1.name = 'Top 1'
>>> top1.save()

>>> bot1 = Level3()
>>> bot1.name = 'Bot 1'
>>> bot1.save()

>>> l1 = Level1.objects.all()
>>> l1
[<Level1: Level1 object>, <Level1: Level1 object>]

>>> l2 = Level2.objects.all()
>>> l2
[<Level2: Level2 object>]

>>> l3 = Level3.objects.all()
>>> l3
[<Level3: Level3 object>]

>>> l1[0].name
u'Top 1'

>>> l1[1].name
u'Bot 1'

>>> l2[0].name
u'Bot 1'

>>> l3[0].name
u'Top 1' # WRONG!! - expected value is u'Bot
1'

}}}

Note: In this example OneToOneField and ID/primary keys are manually added
so that specific db_column names can be used. It is unclear whether the
problem is related to this combination, or whether it affects auto-
generated OneToOneFields as well.

--
Ticket URL: <https://code.djangoproject.com/ticket/20776>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Jul 22, 2013, 4:06:31 PM7/22/13
to django-...@googlegroups.com
#20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns
-------------------------------------+-------------------------------------

Reporter: dowstreet@… | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 1.5
Severity: Normal | Resolution:
Keywords: Muti-table | Triage Stage:
Inheritance | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by akaariai):

* needs_better_patch: => 0
* needs_tests: => 0
* needs_docs: => 0


Comment:

I believe the problem is having level2_id in Level2, and level2
OneToOneField in Level3. OneToOneFields store the related instance in
field.name (level2) and the raw database value in field.attname
(level2_id). The level2 field's attname conflicts with level2_id field
name in Level2.

I am not 100% sure if this is the case. You could test this by changing
the name of level2_id to something else in Level2. If the reason is the
naming conflict this looks like something that could be dealt with in the
validation GSoC project.

--
Ticket URL: <https://code.djangoproject.com/ticket/20776#comment:1>

Django

unread,
Oct 22, 2013, 2:09:57 PM10/22/13
to django-...@googlegroups.com
#20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns
-------------------------------------+-------------------------------------
Reporter: dowstreet@… | Owner: nobody
Type: | Status: new
Cleanup/optimization | Version: 1.5
Component: Database layer | Resolution:
(models, ORM) | Triage Stage: Accepted
Severity: Normal | Needs documentation: 0
Keywords: Muti-table | Patch needs improvement: 0
Inheritance | UI/UX: 0
Has patch: 0 |
Needs tests: 0 |
Easy pickings: 0 |
-------------------------------------+-------------------------------------
Changes (by timo):

* component: Uncategorized => Database layer (models, ORM)
* type: Bug => Cleanup/optimization
* stage: Unreviewed => Accepted


Comment:

@dowstreet, can you provide any further info? I'm going to tentatively
mark it accepted to get it off the unreviewed queue.

--
Ticket URL: <https://code.djangoproject.com/ticket/20776#comment:2>

Django

unread,
Oct 22, 2013, 2:33:12 PM10/22/13
to django-...@googlegroups.com
#20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns
-------------------------------------+-------------------------------------
Reporter: dowstreet@… | Owner: nobody

Type: | Status: new
Cleanup/optimization | Version: 1.5
Component: Database layer | Resolution:
(models, ORM) | Triage Stage: Accepted
Severity: Normal | Needs documentation: 0
Keywords: Muti-table | Patch needs improvement: 0
Inheritance | UI/UX: 0
Has patch: 0 |
Needs tests: 0 |
Easy pickings: 0 |
-------------------------------------+-------------------------------------

Comment (by dowstreet@…):

It looks like the problem occurs if a separate PK is defined in each child
class distinct from the OneToOneField pointing to the parent class. If
instead the OneToOneField is used as the PK in the child class then
everything seems to work. Maybe this is ok - i.e. one is a valid
configuration and one is not? We had initially configured a separate PK
in order to match a legacy database (but ended up changing that schema) -
not sure if there is a standard schema design for other (non-django)
software that uses similar class hierarchy.

--
Ticket URL: <https://code.djangoproject.com/ticket/20776#comment:3>

Django

unread,
Oct 2, 2015, 6:14:20 PM10/2/15
to django-...@googlegroups.com
#20776: Multi-level Multi-table Inheritance - mismatched PKs / explicit db_columns
-------------------------------------+-------------------------------------
Reporter: dowstreet@… | Owner: nobody
Type: | Status: closed
Cleanup/optimization |
Component: Database layer | Version: 1.5
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: Muti-table | Triage Stage: Accepted
Inheritance |

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by timgraham):

* status: new => closed
* resolution: => invalid


Comment:

These models don't validate, so closing as invalid.
{{{
System check identified some issues:
ERRORS:
t20776.Level2.level1: (models.E006) The field 'level1' clashes with the
field 'level1_id' from model 't20776.level1'.
t20776.Level3.level2: (models.E006) The field 'level2' clashes with the
field 'level2' from model 't20776.level1'.
t20776.Level3: (models.E005) The field 'level1' from parent model
't20776.level2' clashes with the field 'level1_id' from parent model
't20776.level1'.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/20776#comment:4>

Reply all
Reply to author
Forward
0 new messages