Skip to content

Commit ad1f1ff

Browse files
committed
fixing a bug where fluent attribute access on ForeignKey columns wasn't working if using a lazy reference
1 parent 79d416c commit ad1f1ff

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

piccolo/columns/column_types.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
)
1818
from piccolo.columns.defaults.uuid import UUID4, UUIDArg
1919
from piccolo.columns.operators.string import ConcatPostgres, ConcatSQLite
20-
from piccolo.columns.reference import LazyTableReference
20+
from piccolo.columns.reference import (
21+
LAZY_COLUMN_REFERENCES,
22+
LazyTableReference,
23+
)
2124
from piccolo.querystring import QueryString, Unquoted
2225
from piccolo.utils.encoding import dump_json
2326

@@ -1041,14 +1044,40 @@ def __init__(
10411044
Table, OnDelete.cascade, OnUpdate.cascade
10421045
)
10431046

1047+
def set_proxy_columns(self):
1048+
"""
1049+
In order to allow a fluent interface, where tables can be traversed
1050+
using ForeignKeys (e.g. ``Band.manager.name``), we add attributes to
1051+
the ``ForeignKey`` column for each column in the table being pointed
1052+
to.
1053+
"""
1054+
_foreign_key_meta = object.__getattribute__(self, "_foreign_key_meta")
1055+
for column in _foreign_key_meta.resolved_references._meta.columns:
1056+
_column: Column = copy.deepcopy(column)
1057+
setattr(self, _column._meta.name, _column)
1058+
_foreign_key_meta.proxy_columns.append(_column)
1059+
10441060
def __getattribute__(self, name: str):
10451061
"""
10461062
Returns attributes unmodified unless they're Column instances, in which
10471063
case a copy is returned with an updated call_chain (which records the
10481064
joins required).
10491065
"""
1050-
# see if it has an attribute with that name ...
1051-
# if it's asking for a foreign key ... return a copy of self ...
1066+
# If the ForeignKey is using a lazy reference, we need to set the
1067+
# attributes here. Attributes starting with a double underscore are
1068+
# unlikely to be column names.
1069+
if not name.startswith("__"):
1070+
try:
1071+
_foreign_key_meta = object.__getattribute__(
1072+
self, "_foreign_key_meta"
1073+
)
1074+
except AttributeError:
1075+
pass
1076+
else:
1077+
if _foreign_key_meta.proxy_columns == [] and isinstance(
1078+
_foreign_key_meta.references, LazyTableReference
1079+
):
1080+
object.__getattribute__(self, "set_proxy_columns")()
10521081

10531082
try:
10541083
value = object.__getattribute__(self, name)

piccolo/table.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,7 @@ def __init_subclass__(
235235
# Allow columns on the referenced table to be accessed via
236236
# auto completion.
237237
if is_table_class:
238-
# We can only do this currently if a Table subclass is
239-
# specified - lazy references don't work. It's a nice to have,
240-
# so not the end of the world.
241-
for column in references._meta.columns:
242-
_column: Column = copy.deepcopy(column)
243-
setattr(foreign_key_column, _column._meta.name, _column)
244-
foreign_key_column._foreign_key_meta.proxy_columns.append(
245-
_column
246-
)
238+
foreign_key_column.set_proxy_columns()
247239

248240
def __init__(self, ignore_missing: bool = False, **kwargs):
249241
"""

tests/columns/test_foreignkey.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,14 @@ def test_lazy_reference_to_app(self):
106106
table_class_name="Manager", app_name="example_app"
107107
)
108108
self.assertTrue(reference.resolve() is Manager)
109+
110+
111+
class TestAttributeAccess(TestCase):
112+
def test_attribute_access(self):
113+
"""
114+
Make sure that attribute access still works correctly with lazy
115+
references.
116+
"""
117+
self.assertTrue(isinstance(Band1.manager.name, Varchar))
118+
self.assertTrue(isinstance(Band2.manager.name, Varchar))
119+
self.assertTrue(isinstance(Band3.manager.name, Varchar))

0 commit comments

Comments
 (0)