Opened 4 years ago

Closed 4 years ago

#15993 closed Bug (duplicate)

Model multiple inheritance primary key reuse

Reported by: erw Owned by: nobody
Component: Database layer (models, ORM) Version: 1.3
Severity: Normal Keywords: model multiple inheritance primary key
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX:

Description

This is easiest to explain with an example.

Using the following models the primary keys may be reused for unrelated objects in the Base table.

class Base(models.Model):
	def __unicode__(self):
		return '(id %d)' % (self.id)

class OtherBase(models.Model):
	def __unicode__(self):
		return '(id %d)' % (self.id)

class ChildOne(Base):
	pass

class ChildTwo(OtherBase, Base):
	pass

Here are sessions demonstrating the behaviors with three different parentages for ChildTwo. Each session starts with a fresh database.

# With ChildTwo(Base)
In [1]: from someapp.models import *
In [2]: ChildOne.objects.create()
Out[2]: <ChildOne: (id 1)>

In [3]: ChildTwo.objects.create()
Out[3]: <ChildTwo: (id 2)>

In [4]: Base.objects.all()
Out[4]: [<Base: (id 1)>, <Base: (id 2)>]

# As expected


# With ChildTwo(Base, OtherBase)
In [1]: from someapp.models import *
In [2]: ChildOne.objects.create()
Out[2]: <ChildOne: (id 1)>

In [3]: ChildTwo.objects.create()
Out[3]: <ChildTwo: (id 2)>

In [4]: Base.objects.all()
Out[4]: [<Base: (id 1)>, <Base: (id 2)>]

In [5]: OtherBase.objects.all()
Out[5]: [<OtherBase: (id 2)>]

# As expected


# With ChildTwo(OtherBase, Base)
In [1]: from someapp.models import *
In [2]: ChildOne.objects.create()
Out[2]: <ChildOne: (id 1)>

In [3]: ChildTwo.objects.create()
Out[3]: <ChildTwo: (id 1)>

In [4]: Base.objects.all()
Out[4]: [<Base: (id 1)>]

In [5]: OtherBase.objects.all()
Out[5]: [<OtherBase: (id 1)>]

# Not expected, the two objects share the id!


# With ChildTwo(OtherBase, Base), creating a ChildTwo instance first
In [1]: from someapp.models import *
In [2]: ChildTwo.objects.create()
Out[2]: <ChildTwo: (id 1)>

In [3]: ChildOne.objects.create()
Out[3]: <ChildOne: (id 2)>

In [4]: Base.objects.all()
Out[4]: [<Base: (id 1)>, <Base: (id 2)>]

In [5]: OtherBase.objects.all()
Out[5]: [<OtherBase: (id 1)>]

# As expected


# Continuing...
In [6]: ChildTwo.objects.create()
Out[6]: <ChildTwo: (id 2)>

# Again, an id reuse.

In general the ChildTwo creation just picks the next available id in OtherBase without checking if it's free in Base.

This was observed using Django 1.3.0 and behavior was the same for both sqlite3 (3.7.2) and mysql (5.1.49).

Change History (1)

comment:1 Changed 4 years ago by kmtracey

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to duplicate
  • Status changed from new to closed

This looks like a dupe of #12002.

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