Skip to content

Commit 31737a6

Browse files
committed
Workaround for when FK rel field is itself an FK.
1 parent 617c924 commit 31737a6

2 files changed

Lines changed: 47 additions & 4 deletions

File tree

playhouse/migrations.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,9 +332,13 @@ def _build_stub(model, fields, imports):
332332
meta = model._meta
333333
lines = ['class %s(Model):' % model.__name__]
334334
for field in fields:
335-
lines.append(' %s = %s' % (
336-
field.name,
337-
_build_field(field, imports, [])))
335+
if isinstance(field, ForeignKeyField):
336+
# A pk that is itself a fk stores a plain integer.
337+
source = 'IntegerField(primary_key=True, column_name=%r)' % (
338+
field.column_name)
339+
else:
340+
source = _build_field(field, imports, [])
341+
lines.append(' %s = %s' % (field.name, source))
338342
lines.append(' class Meta:')
339343
lines.append(' database = db')
340344
lines.append(' table_name = %r' % meta.table_name)

tests/schema_diff.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ class Meta:
102102
table_name = 'sd_badge'
103103

104104

105+
class SdAccount(TestModel):
106+
label = CharField()
107+
108+
class Meta:
109+
table_name = 'sd_account'
110+
111+
112+
class SdSettings(TestModel):
113+
# One-to-one extension: the pk is itself an fk.
114+
account = ForeignKeyField(SdAccount, primary_key=True)
115+
theme = CharField()
116+
117+
class Meta:
118+
table_name = 'sd_settings'
119+
120+
105121
@skip_if(IS_CRDB, 'crdb introspection differs')
106122
class TestSchemaDiff(ModelTestCase):
107123
requires = SD_MODELS
@@ -571,7 +587,8 @@ def tearDown(self):
571587
try:
572588
shutil.rmtree(self.dir, ignore_errors=True)
573589
self.database.drop_tables([self.runner.History], safe=True)
574-
for table in ('sd_badge', 'sd_slug', 'sd_tag', 'sd_sku',
590+
for table in ('sd_theme', 'sd_settings', 'sd_account',
591+
'sd_badge', 'sd_slug', 'sd_tag', 'sd_sku',
575592
'sd_profile', 'sd_alias', 'sd_kv'):
576593
self.database.execute_sql('DROP TABLE IF EXISTS %s' % table)
577594
finally:
@@ -715,6 +732,28 @@ def test_fk_stub(self):
715732
diff = diff_models(self.database, models)
716733
self.assertEqual(diff.create_tables, [SdBadge])
717734

735+
@requires_models(SdAccount, SdSettings)
736+
def test_fk_stub_pk_fk(self):
737+
# sd_settings' pk is itself an fk. The stub renders it as a
738+
# plain integer rather than recursing into sd_account.
739+
class SdTheme(TestModel):
740+
settings = ForeignKeyField(SdSettings)
741+
name = CharField()
742+
743+
class Meta:
744+
table_name = 'sd_theme'
745+
746+
models = [SdTheme, SdSettings, SdAccount] + SD_MODELS
747+
body = template(diff_models(self.database, models))
748+
self.assertIn("account = IntegerField(primary_key=True, "
749+
"column_name='account_id')", body)
750+
self.apply(body, 'theme')
751+
self.assertFalse(diff_models(self.database, models))
752+
753+
self.assertEqual(self.runner.down(), ['0001_theme'])
754+
self.assertEqual(diff_models(self.database, models).create_tables,
755+
[SdTheme])
756+
718757
def test_autofield_alias(self):
719758
# The aliased pk must render or the table never converges.
720759
class SdAlias(TestModel):

0 commit comments

Comments
 (0)