-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reverse lookup #599
base: master
Are you sure you want to change the base?
Reverse lookup #599
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #599 +/- ##
==========================================
- Coverage 91.35% 91.33% -0.02%
==========================================
Files 108 109 +1
Lines 7517 7629 +112
==========================================
+ Hits 6867 6968 +101
- Misses 650 661 +11 ☔ View full report in Codecov by Sentry. |
Thanks for this! It looks very promising. |
Thanks. I used a lot of code (with some modifications) from M2M fields. I tried to use the best names of variables and methods. The main obstacle is that the user would have to enter |
Just wanted to note that there is interest in this functionality. Is there anything specific holding this back (from being merged)? Also I like how in peewee one can just set the |
piccolo/columns/reverse_lookup.py
Outdated
i._meta.name | ||
for i in reverse_lookup_table._meta.foreign_key_columns | ||
] | ||
return fk_columns.index(self.table._meta.tablename) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like we compare column names with table names here. They don't have to match. I think instead of
Manager.artists(table=Manager)
it would be better to be able to specify:
Manager.artists(column="manager")
Since the column that is used for the reverse lookup doesn't change(?), I think it would be best if we could also specify it in the ReverseLookup
constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@powellnorma Thanks for your interest and review. It's been a while since I wrote this code, but if I remeber it has to be a table because we refer to the foreign key of parent table later in the code. We need this function to find the foreign key column index if there are multiple foreign keys per single table.
I haven't had chance to review it yet - but I agree that it's a feature we need. |
piccolo/columns/reverse_lookup.py
Outdated
reverse_lookup_fk_table_name = ( | ||
reverse_lookup_table._meta.foreign_key_columns[ | ||
self.foreign_key_columns_index | ||
]._meta.name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think instead of _meta.name
it should be _meta.table._meta.tablename
. Otherwise reverse_lookup_fk_table_name
is a column name
piccolo/columns/reverse_lookup.py
Outdated
SELECT | ||
"{reverse_lookup_table_name}"."{column_name}" | ||
FROM {reverse_select} | ||
) AS "{reverse_lookup_table_name}s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use AS "{original_column_name}s"
. The table must give us that name. See m2m.py:
piccolo/piccolo/columns/m2m.py
Line 93 in 14012e5
) AS "{m2m_relationship_name}" |
@dantownsend It would be great if you could find the time to review this. @powellnorma This code works and passes all tests. If you think that things should be changed, it would be best after Daniel's review. Thank you both. |
piccolo/columns/reverse_lookup.py
Outdated
reverse_select = f""" | ||
"{reverse_lookup_table_name}" | ||
JOIN "{reverse_lookup_fk_table_name}" "inner_{reverse_lookup_fk_table_name}" ON ( | ||
"{reverse_lookup_table_name}"."{reverse_lookup_fk}" | ||
= "inner_{reverse_lookup_fk_table_name}"."{reverse_lookup_pk}" | ||
) WHERE "{reverse_lookup_table_name}"."{reverse_lookup_fk}" | ||
= "{reverse_lookup_fk_table_name}"."{reverse_lookup_pk}" | ||
""" # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this JOIN
here? Isn't the following enough?
reverse_select = f"""
"{reverse_lookup_table_name}"
WHERE "{reverse_lookup_table_name}"."{reverse_lookup_fk}"
= "{reverse_lookup_fk_table_name}"."{reverse_lookup_pk}"
"""
I haven't looked, but I guess the tests always use a ForeignKey named the same as the referenced Table. As e.g. here: class Manager(Table):
name = Varchar()
class Artist(Table):
name = Varchar()
manager = ForeignKey(Manager) But if this is not true, as e.g. here: class MainManager(Table):
name = Varchar()
class Artist(Table):
name = Varchar()
manager = ForeignKey(MainManager) the sections I pointed lead to errors / wrong queries |
When I query an M2M field of the referenced table, I get: AttributeError: type object 'M2MSelect' has no attribute 'value_type' |
Make it work when the ForeignKey is named differently than the referenced Table.
I have fixed the parts that I reviewed on my branch However querying an M2M field (of the referenced table) seems to be rather slow at the moment. When I set |
I'm sorry, but I don't understand. How can we refer to a table that doesn't exist. Shouldn't it be like this class MainManager(Table):
name = Varchar()
class Artist(Table):
name = Varchar()
manager = ForeignKey(MainManager) I want to try your branch. In my reverse lookup attempt I use class Manager(Table):
name = Varchar()
bands = ReverseLookup(
LazyTableReference("Band", module_path=__name__),
)
class Band(Table):
name = Varchar()
manager = ForeignKey(Manager)
# query for all managers bands
query = await Manager.select(
Manager.name, Manager.bands(Band.name, as_list=True, table=Manager)
) Can you show me how to write a table schema and an example query because right now I get |
The example I gave was wrong, I corrected it. What I meant was a situation in which the column name (of the foreign key) has a different name than the table that it refers to
Like this: class MainManager(Table):
name = Varchar()
artists = ReverseLookup(LazyTableReference("Artist", module_path=__name__), "manager")
class Artist(Table):
name = Varchar()
manager = ForeignKey(MainManager)
# select:
await MainManager.select(MainManager.artists(Artist.name)) |
You are right, it doesn't work if the column is different from the table name. I tried to use
This also doesn't work. Raise |
Hm, for me that example works. I (already) made changes so that |
Sorry, that was my mistake. I tried everything from scratch because I probably messed something up and you are right, the tests from my PR pass with your code. |
Does it still occur after this commit? sinisaos@d6c6453 |
Reverse lookup: some fixes for PR
@powellnorma I have added your changes. Thanks again for your help. |
Hi, just wonder what's the status quo of this PR, as it's been around for a long time. Are there any blockers left? I'd really love to see this feature getting merged. Thanks you guys in advance. |
@lqmanh Will try and get this merged in soon. It just needs reviewing in detail to make sure we're happy with the API 👍 |
One thing this is currently missing is the ability to use |
Wow, I'm waiting for this PR. |
it would be cool to have reverse lookup in the api, cant wait for it |
OK, seems like a lot of people want this. Getting Piccolo v1 out has taken most of my attention. Will take another look at this once I've released Python 3.12 support. Bear with me, I know this PR has been around for a while 🙏 |
You guys are doing well. |
Related to #378. Prototype for reverse foreign key lookup. Any suggestions and help are welcome. If I missed the point or it's not a good api design feel free to close PR.
Usage of reverse FK lookup: