I need to create a table with m2m field references to itself #265
-
I need to create a table User with m2m field references to the table User itself I have this table User. Each user may have a friends, and this is peer-to-peer bounds. To describe this bounds between users, i created this tables: class User(Table, tablename="zeem_auth_app_user"):
id = Integer(primary_key=True)
nickname = Varchar(length=36, null=True)
friends = M2M(LazyTableReference("Friends", module_path=__name__))
followers = M2M(LazyTableReference("Fuhrership", module_path=__name__))
fuhrers = M2M(LazyTableReference("Fuhrership", module_path=__name__))
class Fuhrership(Table, tablename="zeem_auth_app_fuhrership"):
follower_id = ForeignKey(User)
fuhrer_id = ForeignKey(User)
datetime_joined = Timestamptz()
class Friends(Table, tablename="zeem_auth_app_user_friends"):
from_user_id = ForeignKey(User)
to_user_id = ForeignKey(User) but this is not worked, i receive File ~\job\zeem-publish-worker\venv\Lib\site-packages\piccolo\columns\m2m.py:285, in M2MAddRelated._run(self)
274 joining_table_row = joining_table(**self.extra_column_values)
275 setattr(
276 joining_table_row,
277 self.m2m._meta.primary_foreign_key._meta.name,
(...)
281 ),
282 )
283 setattr(
284 joining_table_row,
--> 285 self.m2m._meta.secondary_foreign_key._meta.name,
286 getattr(
287 row,
288 row._meta.primary_key._meta.name,
289 ),
290 )
291 joining_table_rows.append(joining_table_row)
293 return await joining_table.insert(*joining_table_rows).run()
File ~\job\zeem-publish-worker\venv\Lib\site-packages\piccolo\columns\m2m.py:240, in M2MMeta.secondary_foreign_key(self)
237 if fk_column._foreign_key_meta.resolved_references != self.table:
238 return fk_column
--> 240 raise ValueError("No matching foreign key column found!")
ValueError: No matching foreign key column found! while i am trying to add users to followers or friends fields u1: User = await User.objects().get(User.id == 1)
u2: User = await User.objects().get(User.id == 2)
await u1.add_m2m(u2, m2m=User.followers)
await u1.add_m2m(u2, m2m=User.friends) (it is the same error to add user to any field) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 10 replies
-
@serg-yalosovetsky Based on this old discussion, I don't think that's possible right now. Maybe you can patch your local Piccolo installation to try this out and see if this suits your needs. # in piccolo/columns/m2m.py
def get_select_string(self, engine_type: str, with_alias=True) -> str:
m2m_table_name_with_schema = (
self.m2m._meta.resolved_joining_table._meta.get_formatted_tablename() # noqa: E501
) # noqa: E501
m2m_relationship_name = self.m2m._meta.name
fk_1 = self.m2m._meta.primary_foreign_key
fk_1_name = fk_1._meta.db_column_name
table_1 = fk_1._foreign_key_meta.resolved_references
table_1_name = table_1._meta.tablename
table_1_name_with_schema = table_1._meta.get_formatted_tablename()
table_1_pk_name = table_1._meta.primary_key._meta.db_column_name
fk_2 = self.m2m._meta.secondary_foreign_key
fk_2_name = fk_2._meta.db_column_name
table_2 = fk_2._foreign_key_meta.resolved_references
# if primary and secondary table are the same
if table_1 == table_2:
table_2_name = table_1._meta.tablename
table_2_name_with_schema = table_1._meta.get_formatted_tablename()
table_2_pk_name = table_1._meta.primary_key._meta.db_column_name
inner_select = f"""
{m2m_table_name_with_schema}
JOIN {table_1_name_with_schema} "inner_{table_1_name}" ON (
{m2m_table_name_with_schema}."{fk_1_name}" = "inner_{table_1_name}"."{table_1_pk_name}"
)
WHERE {m2m_table_name_with_schema}."{fk_1_name}" = "{table_1_name}"."{table_1_pk_name}"
""" # noqa: E501
else:
table_2_name = table_2._meta.tablename
table_2_name_with_schema = table_2._meta.get_formatted_tablename()
table_2_pk_name = table_2._meta.primary_key._meta.db_column_name
inner_select = f"""
{m2m_table_name_with_schema}
JOIN {table_1_name_with_schema} "inner_{table_1_name}" ON (
{m2m_table_name_with_schema}."{fk_1_name}" = "inner_{table_1_name}"."{table_1_pk_name}"
)
JOIN {table_2_name_with_schema} "inner_{table_2_name}" ON (
{m2m_table_name_with_schema}."{fk_2_name}" = "inner_{table_2_name}"."{table_2_pk_name}"
)
WHERE {m2m_table_name_with_schema}."{fk_1_name}" = "{table_1_name}"."{table_1_pk_name}"
""" # noqa: E501
...
# and later
@property
def secondary_foreign_key(self) -> ForeignKey:
"""
See ``primary_foreign_key``.
"""
# if primary and secondary table are the same
for fk_column in self.foreign_key_columns:
if fk_column._foreign_key_meta.resolved_references != self.table:
return fk_column
if (
fk_column._foreign_key_meta.resolved_references
== self.primary_table
):
return self.foreign_key_columns[-1]
raise ValueError("No matching foreign key column found!") |
Beta Was this translation helpful? Give feedback.
@serg-yalosovetsky Based on this old discussion, I don't think that's possible right now. Maybe you can patch your local Piccolo installation to try this out and see if this suits your needs.