When a ForeignKeyField/OneToOneField is declared with a to_field that points to a non-primary-key column, filtering by a related model instance used the instance's primary key instead of the to_field value.
In Q._get_actual_filter_params, the fk/o2o branch did filter_value = getattr(value, "pk", value), hardcoding .pk. So for a FK with to_field="app_id", Model.filter(fk=instance) generated SQL comparing the <fk>_id column (which stores the to_field value) against instance.pk, targeting the wrong value and, when the types differ (e.g. a UUID pk vs an int to_field), raising type errors or silently returning wrong results.
This resolves the to_field column via field_object.to_field_instance.model_field_name and reads that attribute off the instance. For the default case where to_field is the primary key, to_field_instance.model_field_name is the pk attribute, so getattr returns value.pk exactly as before; raw-value filters (filter(fk=7)) still fall through to the value via getattr's default.
The existing test models already expose this shape: School's primary key is uuid, while Student.school uses to_field="id" (a non-pk unique field). The added regression test in tests/test_relations_with_unique.py creates a School whose id differs from its pk and asserts Student.filter(school=school) finds the student; it fails on the current code (filters by the pk) and passes with this change. The full test_relations and test_relations_with_unique suites pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2225
When a ForeignKeyField/OneToOneField is declared with a to_field that points to a non-primary-key column, filtering by a related model instance used the instance's primary key instead of the to_field value.
In Q._get_actual_filter_params, the fk/o2o branch did filter_value = getattr(value, "pk", value), hardcoding .pk. So for a FK with to_field="app_id", Model.filter(fk=instance) generated SQL comparing the <fk>_id column (which stores the to_field value) against instance.pk, targeting the wrong value and, when the types differ (e.g. a UUID pk vs an int to_field), raising type errors or silently returning wrong results.
This resolves the to_field column via field_object.to_field_instance.model_field_name and reads that attribute off the instance. For the default case where to_field is the primary key, to_field_instance.model_field_name is the pk attribute, so getattr returns value.pk exactly as before; raw-value filters (filter(fk=7)) still fall through to the value via getattr's default.
The existing test models already expose this shape: School's primary key is uuid, while Student.school uses to_field="id" (a non-pk unique field). The added regression test in tests/test_relations_with_unique.py creates a School whose id differs from its pk and asserts Student.filter(school=school) finds the student; it fails on the current code (filters by the pk) and passes with this change. The full test_relations and test_relations_with_unique suites pass.