Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #21664: Multi-table inheritance was duplicating _ptr fields

  • Loading branch information...
commit 3f1a008266e8797ae104905b4d3168fa2a33b9ae 1 parent 1f5268a
@andrewgodwin andrewgodwin authored
View
2  django/db/migrations/writer.py
@@ -194,7 +194,7 @@ def serialize(cls, value):
if isinstance(value, set):
format = "set([%s])"
elif isinstance(value, tuple):
- format = "(%s)" if len(value) else "(%s,)"
+ format = "(%s)" if len(value) > 1 else "(%s,)"
else:
format = "[%s]"
return format % (", ".join(strings)), imports
View
5 django/db/models/base.py
@@ -251,7 +251,10 @@ def __new__(cls, name, bases, attrs):
attr_name = '%s_ptr' % base._meta.model_name
field = OneToOneField(base, name=attr_name,
auto_created=True, parent_link=True)
- new_class.add_to_class(attr_name, field)
+ # Only add the ptr field if it's not already present;
+ # e.g. migrations will already have it specified
+ if not hasattr(new_class, attr_name):
+ new_class.add_to_class(attr_name, field)
else:
field = None
new_class._meta.parents[base] = field
View
32 tests/migrations/test_operations.py
@@ -90,6 +90,38 @@ def test_create_model(self):
self.assertEqual(len(definition[2]), 0)
self.assertEqual(definition[1][0], "Pony")
+ def test_create_model_inheritance(self):
+ """
+ Tests the CreateModel operation on a multi-table inheritance setup.
+ """
+ project_state = self.set_up_test_model("test_crmoih")
+ # Test the state alteration
+ operation = migrations.CreateModel(
+ "ShetlandPony",
+ [
+ ('pony_ptr', models.OneToOneField(
+ auto_created=True,
+ primary_key=True,
+ to_field=u'id',
@charettes Collaborator

Python 3.2 doesn't like unicode literals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ serialize=False,
+ to='test_crmoih.Pony',
+ )),
+ ("cuteness", models.IntegerField(default=1)),
+ ],
+ )
+ new_state = project_state.clone()
+ operation.state_forwards("test_crmoih", new_state)
+ self.assertIn(("test_crmoih", "shetlandpony"), new_state.models)
+ # Test the database alteration
+ self.assertTableNotExists("test_crmoih_shetlandpony")
+ with connection.schema_editor() as editor:
+ operation.database_forwards("test_crmoih", editor, project_state, new_state)
+ self.assertTableExists("test_crmoih_shetlandpony")
+ # And test reversal
+ with connection.schema_editor() as editor:
+ operation.database_backwards("test_crmoih", editor, new_state, project_state)
+ self.assertTableNotExists("test_crmoih_shetlandpony")
+
def test_delete_model(self):
"""
Tests the DeleteModel operation.
View
31 tests/migrations/test_state.py
@@ -33,6 +33,12 @@ class Meta:
proxy = True
ordering = ["name"]
+ class SubAuthor(Author):
+ width = models.FloatField(null=True)
+ class Meta:
+ app_label = "migrations"
+ apps = new_apps
+
class Book(models.Model):
title = models.CharField(max_length=1000)
author = models.ForeignKey(Author)
@@ -47,6 +53,7 @@ class Meta:
project_state = ProjectState.from_apps(new_apps)
author_state = project_state.models['migrations', 'author']
author_proxy_state = project_state.models['migrations', 'authorproxy']
+ sub_author_state = project_state.models['migrations', 'subauthor']
book_state = project_state.models['migrations', 'book']
self.assertEqual(author_state.app_label, "migrations")
@@ -55,7 +62,7 @@ class Meta:
self.assertEqual(author_state.fields[1][1].max_length, 255)
self.assertEqual(author_state.fields[2][1].null, False)
self.assertEqual(author_state.fields[3][1].null, True)
- self.assertEqual(author_state.options, {"unique_together": {("name", "bio")}})
+ self.assertEqual(author_state.options, {"unique_together": set([("name", "bio")])})
self.assertEqual(author_state.bases, (models.Model, ))
self.assertEqual(book_state.app_label, "migrations")
@@ -73,6 +80,11 @@ class Meta:
self.assertEqual(author_proxy_state.options, {"proxy": True, "ordering": ["name"]})
self.assertEqual(author_proxy_state.bases, ("migrations.author", ))
+ self.assertEqual(sub_author_state.app_label, "migrations")
+ self.assertEqual(sub_author_state.name, "SubAuthor")
+ self.assertEqual(len(sub_author_state.fields), 2)
+ self.assertEqual(sub_author_state.bases, ("migrations.author", ))
+
def test_render(self):
"""
Tests rendering a ProjectState into an Apps.
@@ -89,10 +101,27 @@ def test_render(self):
{},
None,
))
+ project_state.add_model_state(ModelState(
+ "migrations",
+ "SubTag",
+ [
+ ('tag_ptr', models.OneToOneField(
+ auto_created=True,
+ primary_key=True,
+ to_field=u'id',
@charettes Collaborator

Idem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ serialize=False,
+ to='migrations.Tag',
+ )),
+ ("awesome", models.BooleanField()),
+ ],
+ options={},
+ bases=("migrations.Tag",),
+ ))
new_apps = project_state.render()
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("name")[0].max_length, 100)
self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("hidden")[0].null, False)
+ self.assertEqual(len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2)
def test_render_model_inheritance(self):
class Book(models.Model):
@charettes

Python 3.2 doesn't like unicode literals.

Please sign in to comment.
Something went wrong with that request. Please try again.