From 05c7129bf28f243785d5a82701a5ebd865828c28 Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Wed, 22 Jul 2015 11:54:42 -0700 Subject: [PATCH] [1.8.x] Fixed #12768 -- Fixed QuerySet.raw() regression on FK with custom db_column. Backport of e063ac2fae007a2eecaeab5ce17064c31230ce29 from master --- django/db/models/query.py | 6 +++--- docs/releases/1.8.4.txt | 4 ++++ tests/raw_query/models.py | 4 ++++ tests/raw_query/tests.py | 14 +++++++++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index b055205772..4163ce9e6d 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1267,11 +1267,11 @@ class RawQuerySet(object): """ Resolve the init field names and value positions """ - model_init_names = [f.attname for f in self.model._meta.fields - if f.attname in self.columns] + model_init_fields = [f for f in self.model._meta.fields if f.column in self.columns] annotation_fields = [(column, pos) for pos, column in enumerate(self.columns) if column not in self.model_fields] - model_init_order = [self.columns.index(fname) for fname in model_init_names] + model_init_order = [self.columns.index(f.column) for f in model_init_fields] + model_init_names = [f.attname for f in model_init_fields] return model_init_names, model_init_order, annotation_fields def __iter__(self): diff --git a/docs/releases/1.8.4.txt b/docs/releases/1.8.4.txt index e6606cb37f..81b00c1800 100644 --- a/docs/releases/1.8.4.txt +++ b/docs/releases/1.8.4.txt @@ -14,3 +14,7 @@ Bugfixes * Added a system check warning if the old ``TEMPLATE_*`` settings are defined in addition to the new ``TEMPLATES`` setting. + +* Fixed ``QuerySet.raw()`` so ``InvalidQuery`` is not raised when using the + ``db_column`` name of a ``ForeignKey`` field with ``primary_key=True`` + (:ticket:`12768`). diff --git a/tests/raw_query/models.py b/tests/raw_query/models.py index 1e5e176bcf..2a888088ef 100644 --- a/tests/raw_query/models.py +++ b/tests/raw_query/models.py @@ -23,6 +23,10 @@ class Book(models.Model): opening_line = models.TextField() +class BookFkAsPk(models.Model): + book = models.ForeignKey(Book, primary_key=True, db_column="not_the_default") + + class Coffee(models.Model): brand = models.CharField(max_length=255, db_column="name") diff --git a/tests/raw_query/tests.py b/tests/raw_query/tests.py index 5d2bf4becf..1a9c4715e6 100644 --- a/tests/raw_query/tests.py +++ b/tests/raw_query/tests.py @@ -5,7 +5,7 @@ from datetime import date from django.db.models.query_utils import InvalidQuery from django.test import TestCase, skipUnlessDBFeature -from .models import Author, Book, Coffee, FriendlyAuthor, Reviewer +from .models import Author, Book, BookFkAsPk, Coffee, FriendlyAuthor, Reviewer class RawQueryTests(TestCase): @@ -259,3 +259,15 @@ class RawQueryTests(TestCase): list(Book.objects.raw('SELECT id FROM (SELECT * FROM raw_query_book WHERE paperback IS NOT NULL) sq')) except InvalidQuery: self.fail("Using a subquery in a RawQuerySet raised InvalidQuery") + + def test_db_column_name_is_used_in_raw_query(self): + """ + Regression test that ensures the `column` attribute on the field is + used to generate the list of fields included in the query, as opposed + to the `attname`. This is important when the primary key is a + ForeignKey field because `attname` and `column` are not necessarily the + same. + """ + b1 = Book.objects.latest('id') + b = BookFkAsPk.objects.create(book=b1) + self.assertEqual(list(BookFkAsPk.objects.raw('SELECT not_the_default FROM raw_query_bookfkaspk')), [b])