From dbffffa7dc95fc62cbecfd00284bde62ee796f48 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 28 Jun 2011 10:16:18 +0000 Subject: [PATCH] Fixed #5535 -- Allow using an explicit foreign key in get() calls. Thanks, Michal Petrucha. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16473 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/sql/query.py | 5 ++-- docs/topics/db/queries.txt | 10 ++++++++ tests/modeltests/many_to_one/tests.py | 37 +++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 99663b646b..110e3179d5 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1068,8 +1068,9 @@ class Query(object): try: field, target, opts, join_list, last, extra_filters = self.setup_joins( - parts, opts, alias, True, allow_many, can_reuse=can_reuse, - negate=negate, process_extras=process_extras) + parts, opts, alias, True, allow_many, allow_explicit_fk=True, + can_reuse=can_reuse, negate=negate, + process_extras=process_extras) except MultiJoin, e: self.split_exclude(filter_expr, LOOKUP_SEP.join(parts[:e.level]), can_reuse) diff --git a/docs/topics/db/queries.txt b/docs/topics/db/queries.txt index 3457913011..a4267489b9 100644 --- a/docs/topics/db/queries.txt +++ b/docs/topics/db/queries.txt @@ -365,6 +365,16 @@ translates (roughly) into the following SQL:: .. _`Keyword Arguments`: http://docs.python.org/tutorial/controlflow.html#keyword-arguments +.. versionchanged:: 1.4 + + The field specified in a lookup has to be the name of a model field. + There's one exception though, in case of a + :class:`~django.db.models.fields.ForeignKey` you can specify the field + name suffixed with ``_id``. In this case, the value parameter is expected + to contain the raw value of the foreign model's primary key. For example:: + + >>> Entry.objects.filter(blog_id__exact=4) + If you pass an invalid keyword argument, a lookup function will raise ``TypeError``. diff --git a/tests/modeltests/many_to_one/tests.py b/tests/modeltests/many_to_one/tests.py index 8a2af2157b..83e984dc6d 100644 --- a/tests/modeltests/many_to_one/tests.py +++ b/tests/modeltests/many_to_one/tests.py @@ -2,7 +2,7 @@ from copy import deepcopy from datetime import datetime from django.test import TestCase -from django.core.exceptions import FieldError +from django.core.exceptions import FieldError, MultipleObjectsReturned from models import Article, Reporter @@ -229,10 +229,6 @@ class ManyToOneTests(TestCase): "", "", ]) - # You need two underscores between "reporter" and "id" -- not one. - self.assertRaises(FieldError, Article.objects.filter, reporter_id__exact=self.r.id) - # You need to specify a comparison clause - self.assertRaises(FieldError, Article.objects.filter, reporter_id=self.r.id) def test_reverse_selects(self): a3 = Article.objects.create(id=None, headline="Third article", @@ -372,3 +368,34 @@ class ManyToOneTests(TestCase): # recursive don't cause recursion depth problems under deepcopy. self.r.cached_query = Article.objects.filter(reporter=self.r) self.assertEqual(repr(deepcopy(self.r)), "") + + def test_explicit_fk(self): + # Create a new Article with get_or_create using an explicit value + # for a ForeignKey. + a2, created = Article.objects.get_or_create(id=None, + headline="John's second test", + pub_date=datetime(2011, 5, 7), + reporter_id=self.r.id) + self.assertTrue(created) + self.assertEqual(a2.reporter.id, self.r.id) + + # You can specify filters containing the explicit FK value. + self.assertQuerysetEqual( + Article.objects.filter(reporter_id__exact=self.r.id), + [ + "", + "", + ]) + + # Create an Article by Paul for the same date. + a3 = Article.objects.create(id=None, headline="Paul's commentary", + pub_date=datetime(2011, 5, 7), + reporter_id=self.r2.id) + self.assertEqual(a3.reporter.id, self.r2.id) + + # Get should respect explicit foreign keys as well. + self.assertRaises(MultipleObjectsReturned, + Article.objects.get, reporter_id=self.r.id) + self.assertEqual(repr(a3), + repr(Article.objects.get(reporter_id=self.r2.id, + pub_date=datetime(2011, 5, 7))))