-
Notifications
You must be signed in to change notification settings - Fork 255
impl Add support for Django reverse relationships #2071 #2074
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull request overview
This pull request implements support for Django reverse relationships, addressing issue #2071. The implementation synthesizes reverse accessors for ForeignKey, ManyToManyField, and OneToOneField by scanning model field bindings, inferring reverse accessors, parsing related_name (including template substitution for %(class)s and %(app_label)s), and adding a RelatedManager helper for reverse ForeignKey accessors.
Changes:
- Added reverse relationship field synthesis for Django models
- Implemented related_name template parsing with
%(class)sand%(app_label)ssupport - Added RelatedManager type support for ForeignKey reverse accessors
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pyrefly/lib/alt/class/django.rs | Core implementation of reverse relationship synthesis including relation kind detection, related_name parsing with template substitution, and manager type resolution |
| pyrefly/lib/test/django/foreign_key.rs | Added test assertion for ForeignKey reverse accessor (article_set) on Reporter model |
| pyrefly/lib/test/django/many_to_many.rs | Added test assertion for ManyToManyField reverse accessor (books) on Author model |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This comment has been minimized.
This comment has been minimized.
|
Thank you so much! I will import and take a closer look. |
rchen152
left a comment
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.
Review automatically exported from Phabricator review in Meta.
|
Hello! we got to review the diff in more details. Here are some open questions:
|
|
Moved Django reverse-relationship synthesis to a module-level binding/index so we compute reverse fields once per module (instead of scanning every KeyClassField for each model). The binder now records candidate relation fields during the class-body pass, and the solver builds a reverse-relation index keyed by target class that get_django_model_synthesized_fields can query. |
This comment has been minimized.
This comment has been minimized.
|
Started cross‑module support by building a global reverse‑relation index once per solve and caching it in the thread state. The index merges each module’s KeyDjangoRelations result, so reverse accessors now come from all modules loaded in the current transaction (not just the current module). This required exporting KeyDjangoRelations and adding LookupAnswer::modules() so the solver can enumerate available modules and combine their per‑module indexes. |
This comment has been minimized.
This comment has been minimized.
|
Diff from mypy_primer, showing the effect of this PR on open source code: zulip (https://github.com/zulip/zulip)
- ERROR corporate/views/support.py:943:13-42: Object of class `RemoteZulipServer` has no attribute `remoterealm_set` [missing-attribute]
- ERROR zerver/actions/create_user.py:820:26-52: Object of class `UserProfile` has no attribute `direct_groups` [missing-attribute]
+ ERROR zerver/actions/create_user.py:833:28-55: Object of class `UserGroup` has no attribute `named_user_group` [missing-attribute]
- ERROR zerver/actions/uploads.py:136:44-66: Object of class `Message` has no attribute `attachment_set`
+ ERROR zerver/actions/uploads.py:136:44-66: Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/actions/uploads.py:145:9-31: Object of class `Message` has no attribute `attachment_set`
+ ERROR zerver/actions/uploads.py:145:9-31: Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/actions/uploads.py:157:35-57: Object of class `Message` has no attribute `attachment_set`
+ ERROR zerver/actions/uploads.py:157:35-57: Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- Object of class `ScheduledMessage` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/actions/users.py:433:35-61: Object of class `UserProfile` has no attribute `direct_groups` [missing-attribute]
- ERROR zerver/lib/user_groups.py:778:17-43: Object of class `UserProfile` has no attribute `direct_groups` [missing-attribute]
- ERROR zerver/lib/user_groups.py:862:21-47: Object of class `UserProfile` has no attribute `direct_groups` [missing-attribute]
- ERROR zerver/lib/widget.py:142:12-34: Object of class `Message` has no attribute `submessage_set` [missing-attribute]
- ERROR zerver/management/commands/export_search.py:300:35-57: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/models/realms.py:1377:17-38: Object of class `Realm` has no attribute `realmdomain_set` [missing-attribute]
+ ERROR zerver/models/realms.py:1377:16-76: No matching overload found for function `list.__init__` called with arguments: (QuerySet[RealmDomain, dict[str, Any]]) [no-matching-overload]
- ERROR zerver/tests/test_custom_profile_data.py:460:26-66: Object of class `UserProfile` has no attribute `customprofilefieldvalue_set` [missing-attribute]
- ERROR zerver/tests/test_custom_profile_data.py:465:26-66: Object of class `UserProfile` has no attribute `customprofilefieldvalue_set` [missing-attribute]
- ERROR zerver/tests/test_message_fetch.py:5655:25-43: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/tests/test_message_fetch.py:5656:26-44: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/tests/test_message_fetch.py:5660:25-43: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/tests/test_message_fetch.py:5661:26-44: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ERROR zerver/tests/test_message_fetch.py:5665:26-44: Object of class `Message` has no attribute `attachment_set` [missing-attribute]
- ::error file=corporate/views/support.py,line=943,col=13,endLine=943,endColumn=42,title=Pyrefly missing-attribute::Object of class `RemoteZulipServer` has no attribute `remoterealm_set`
- ::error file=zerver/actions/create_user.py,line=820,col=26,endLine=820,endColumn=52,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `direct_groups`
+ ::error file=zerver/actions/create_user.py,line=833,col=28,endLine=833,endColumn=55,title=Pyrefly missing-attribute::Object of class `UserGroup` has no attribute `named_user_group`
- ::error file=zerver/actions/uploads.py,line=136,col=44,endLine=136,endColumn=66,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`%0AObject of class `ScheduledMessage` has no attribute `attachment_set`
+ ::error file=zerver/actions/uploads.py,line=136,col=44,endLine=136,endColumn=66,title=Pyrefly missing-attribute::Object of class `ScheduledMessage` has no attribute `attachment_set`
- ::error file=zerver/actions/uploads.py,line=145,col=9,endLine=145,endColumn=31,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`%0AObject of class `ScheduledMessage` has no attribute `attachment_set`
+ ::error file=zerver/actions/uploads.py,line=145,col=9,endLine=145,endColumn=31,title=Pyrefly missing-attribute::Object of class `ScheduledMessage` has no attribute `attachment_set`
- ::error file=zerver/actions/uploads.py,line=157,col=35,endLine=157,endColumn=57,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`%0AObject of class `ScheduledMessage` has no attribute `attachment_set`
+ ::error file=zerver/actions/uploads.py,line=157,col=35,endLine=157,endColumn=57,title=Pyrefly missing-attribute::Object of class `ScheduledMessage` has no attribute `attachment_set`
- ::error file=zerver/actions/users.py,line=433,col=35,endLine=433,endColumn=61,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `direct_groups`
- ::error file=zerver/lib/user_groups.py,line=778,col=17,endLine=778,endColumn=43,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `direct_groups`
- ::error file=zerver/lib/user_groups.py,line=862,col=21,endLine=862,endColumn=47,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `direct_groups`
- ::error file=zerver/lib/widget.py,line=142,col=12,endLine=142,endColumn=34,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `submessage_set`
- ::error file=zerver/management/commands/export_search.py,line=300,col=35,endLine=300,endColumn=57,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
- ::error file=zerver/models/realms.py,line=1377,col=17,endLine=1377,endColumn=38,title=Pyrefly missing-attribute::Object of class `Realm` has no attribute `realmdomain_set`
+ ::error file=zerver/models/realms.py,line=1377,col=16,endLine=1377,endColumn=76,title=Pyrefly no-matching-overload::No matching overload found for function `list.__init__` called with arguments: (QuerySet[RealmDomain, dict[str, Any]])%0A Possible overloads:%0A () -> None%0A (iterable: Iterable[RealmDomainDict], /) -> None [closest match]
- ::error file=zerver/tests/test_custom_profile_data.py,line=460,col=26,endLine=460,endColumn=66,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `customprofilefieldvalue_set`
- ::error file=zerver/tests/test_custom_profile_data.py,line=465,col=26,endLine=465,endColumn=66,title=Pyrefly missing-attribute::Object of class `UserProfile` has no attribute `customprofilefieldvalue_set`
- ::error file=zerver/tests/test_message_fetch.py,line=5655,col=25,endLine=5655,endColumn=43,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
- ::error file=zerver/tests/test_message_fetch.py,line=5656,col=26,endLine=5656,endColumn=44,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
- ::error file=zerver/tests/test_message_fetch.py,line=5660,col=25,endLine=5660,endColumn=43,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
- ::error file=zerver/tests/test_message_fetch.py,line=5661,col=26,endLine=5661,endColumn=44,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
- ::error file=zerver/tests/test_message_fetch.py,line=5665,col=26,endLine=5665,endColumn=44,title=Pyrefly missing-attribute::Object of class `Message` has no attribute `attachment_set`
|
Summary
Fixes #2071
Implemented Django reverse relationship synthesis by scanning model field bindings in the module, inferring reverse accessors for ForeignKey/ManyToManyField (and OneToOneField), parsing related_name (including %(class)s/%(app_label)s), and adding a RelatedManager helper for reverse FK accessors.
Notes/limits:
Reverse accessors are synthesized only from relation fields declared in the same module and with literal related_name/None (dynamic names are skipped).
Cross-module reverse inference isn’t covered yet.supported.Test Plan
Added assertions for reverse accessors