diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index 92c1a0fcc3..186e217083 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -176,8 +176,9 @@ class FieldGetDbPrepValueMixin: get_db_prep_lookup_value_is_iterable = False def get_db_prep_lookup(self, value, connection): - # For relational fields, use the output_field of the 'field' attribute. - field = getattr(self.lhs.output_field, 'field', None) + # For relational fields, use the 'target_field' attribute of the + # output_field. + field = getattr(self.lhs.output_field, 'target_field', None) get_db_prep_value = getattr(field, 'get_db_prep_value', None) or self.lhs.output_field.get_db_prep_value return ( '%s', diff --git a/tests/queries/models.py b/tests/queries/models.py index af0af1d10c..eaddba1c8d 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -67,10 +67,15 @@ class Annotation(models.Model): return self.name +class DateTimePK(models.Model): + date = models.DateTimeField(primary_key=True, auto_now_add=True) + + class ExtraInfo(models.Model): info = models.CharField(max_length=100) note = models.ForeignKey(Note, models.CASCADE, null=True) value = models.IntegerField(null=True) + date = models.ForeignKey(DateTimePK, models.SET_NULL, null=True) class Meta: ordering = ['info'] diff --git a/tests/queries/tests.py b/tests/queries/tests.py index bce514c0bf..7e2284e751 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -16,18 +16,19 @@ from .models import ( FK1, Annotation, Article, Author, BaseA, Book, CategoryItem, CategoryRelationship, Celebrity, Channel, Chapter, Child, ChildObjectA, Classroom, CommonMixedCaseForeignKeys, Company, Cover, CustomPk, - CustomPkTag, Detail, DumbCategory, Eaten, Employment, ExtraInfo, Fan, Food, - Identifier, Individual, Item, Job, JobResponsibilities, Join, LeafA, LeafB, - LoopX, LoopZ, ManagedModel, Member, MixedCaseDbColumnCategoryItem, - MixedCaseFieldCategoryItem, ModelA, ModelB, ModelC, ModelD, MyObject, - NamedCategory, Node, Note, NullableName, Number, ObjectA, ObjectB, ObjectC, - OneToOneCategory, Order, OrderItem, Page, Paragraph, Person, Plaything, - PointerA, Program, ProxyCategory, ProxyObjectA, ProxyObjectB, Ranking, - Related, RelatedIndividual, RelatedObject, Report, ReportComment, - ReservedName, Responsibility, School, SharedConnection, SimpleCategory, - SingleObject, SpecialCategory, Staff, StaffUser, Student, Tag, Task, - Teacher, Ticket21203Child, Ticket21203Parent, Ticket23605A, Ticket23605B, - Ticket23605C, TvChef, Valid, X, + CustomPkTag, DateTimePK, Detail, DumbCategory, Eaten, Employment, + ExtraInfo, Fan, Food, Identifier, Individual, Item, Job, + JobResponsibilities, Join, LeafA, LeafB, LoopX, LoopZ, ManagedModel, + Member, MixedCaseDbColumnCategoryItem, MixedCaseFieldCategoryItem, ModelA, + ModelB, ModelC, ModelD, MyObject, NamedCategory, Node, Note, NullableName, + Number, ObjectA, ObjectB, ObjectC, OneToOneCategory, Order, OrderItem, + Page, Paragraph, Person, Plaything, PointerA, Program, ProxyCategory, + ProxyObjectA, ProxyObjectB, Ranking, Related, RelatedIndividual, + RelatedObject, Report, ReportComment, ReservedName, Responsibility, School, + SharedConnection, SimpleCategory, SingleObject, SpecialCategory, Staff, + StaffUser, Student, Tag, Task, Teacher, Ticket21203Child, + Ticket21203Parent, Ticket23605A, Ticket23605B, Ticket23605C, TvChef, Valid, + X, ) @@ -1462,6 +1463,14 @@ class Queries4Tests(TestCase): CategoryItem.objects.create(category=c1) self.assertSequenceEqual(SimpleCategory.objects.order_by('categoryitem', 'pk'), [c1, c2, c1]) + def test_filter_reverse_non_integer_pk(self): + date_obj = DateTimePK.objects.create() + extra_obj = ExtraInfo.objects.create(info='extra', date=date_obj) + self.assertEqual( + DateTimePK.objects.filter(extrainfo=extra_obj).get(), + date_obj, + ) + def test_ticket10181(self): # Avoid raising an EmptyResultSet if an inner query is probably # empty (and hence, not executed).