Skip to content

Commit c5bf643

Browse files
committed
fixing bug with mixins
The Table metaclass now copies columns, otherwise when attributes were set on the columns, it would effect other users of that mixin.
1 parent 62813dc commit c5bf643

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

piccolo/apps/migrations/auto/migration_manager.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,11 @@ async def _run_add_columns(self, backwards=False):
609609
_Table._meta.tablename = add_columns[0].tablename
610610

611611
for add_column in add_columns:
612-
column = add_column.column
612+
# We fetch the column from the Table, as the metaclass
613+
# copies and sets it up properly.
614+
column = _Table._meta.get_column_by_name(
615+
add_column.column._meta.name
616+
)
613617
await _Table.alter().add_column(
614618
name=column._meta.name, column=column
615619
).run()

piccolo/table.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ def __init_subclass__(
172172

173173
attribute = getattr(cls, attribute_name)
174174
if isinstance(attribute, Column):
175-
column = attribute
175+
# We have to copy, then override the existing column
176+
# definition, in case this column is inheritted from a mixin.
177+
# Otherwise, when we set attributes on that column, it will
178+
# effect all other users of that mixin.
179+
column = attribute.copy()
180+
setattr(cls, attribute_name, column)
176181

177182
if isinstance(column, PrimaryKey):
178183
# We want it at the start.
@@ -185,8 +190,8 @@ def __init_subclass__(
185190
column._meta._name = attribute_name
186191
column._meta._table = cls
187192

188-
if isinstance(column, ForeignKey):
189-
foreign_key_columns.append(column)
193+
if isinstance(column, ForeignKey):
194+
foreign_key_columns.append(column)
190195

191196
cls._meta = TableMeta(
192197
tablename=tablename,

tests/table/test_inheritance.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ class Manager(StartedOnMixin, FavouriteMixin, Table):
2525
name = Varchar()
2626

2727

28+
class ManagerA(StartedOnMixin, Table):
29+
name = Varchar()
30+
31+
32+
class ManagerB(StartedOnMixin, Table):
33+
name = Varchar()
34+
35+
2836
class TestInheritance(TestCase):
2937
"""
3038
Make sure columns can be inheritted from parent classes.
@@ -56,3 +64,43 @@ def test_inheritance(self):
5664
self.assertEqual(response["started_on"], started_on)
5765
self.assertEqual(response["name"], name)
5866
self.assertEqual(response["favourite"], favourite)
67+
68+
69+
class TestRepeatedMixin(TestCase):
70+
"""
71+
Make sure that if a mixin is used multiple times (i.e. across several
72+
Table classes), that it still works as expected.
73+
"""
74+
75+
def setUp(self):
76+
ManagerA.create_table().run_sync()
77+
ManagerB.create_table().run_sync()
78+
79+
def tearDown(self):
80+
ManagerA.alter().drop_table().run_sync()
81+
ManagerB.alter().drop_table().run_sync()
82+
83+
def test_inheritance(self):
84+
"""
85+
Make sure both tables work as expected (they both inherit from the
86+
same mixin).
87+
"""
88+
# Make sure the columns can be retrieved from both tables:
89+
for column_name in ("started_on", "name"):
90+
for Table_ in (ManagerA, ManagerB):
91+
Table_._meta.get_column_by_name(column_name)
92+
93+
# Test saving and retrieving data:
94+
started_on = datetime.datetime(year=1989, month=12, day=1)
95+
name = "Guido"
96+
97+
for _Table in (ManagerA, ManagerB):
98+
_Table(name=name, started_on=started_on).save().run_sync()
99+
100+
response = _Table.select().first().run_sync()
101+
self.assertEqual(response["started_on"], started_on)
102+
self.assertEqual(response["name"], name)
103+
104+
# Make sure the tables have the correct tablenames still.
105+
self.assertEqual(ManagerA._meta.tablename, "manager_a")
106+
self.assertEqual(ManagerB._meta.tablename, "manager_b")

0 commit comments

Comments
 (0)