Skip to content

Commit

Permalink
[1.5.x] Fixed #15040 - Boolean fields return 0 and 1 when loaded thro…
Browse files Browse the repository at this point in the history
…ugh select_related

Thanks to homm for the report and ramiro for the patch.

Backport of f3a2bcd from master
  • Loading branch information
spookylukey committed Oct 25, 2012
1 parent 8484972 commit 142f69e
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
12 changes: 11 additions & 1 deletion django/db/models/sql/compiler.py
Expand Up @@ -774,10 +774,20 @@ def results_iter(self):
# We only set this up here because
# related_select_fields isn't populated until
# execute_sql() has been called.

# We also include types of fields of related models that
# will be included via select_related() for the benefit
# of MySQL/MySQLdb when boolean fields are involved
# (#15040).

# This code duplicates the logic for the order of fields
# found in get_columns(). It would be nice to clean this up.
if self.query.select_fields:
fields = self.query.select_fields + self.query.related_select_fields
fields = self.query.select_fields
else:
fields = self.query.model._meta.fields
fields = fields + self.query.related_select_fields

# If the field was deferred, exclude it from being passed
# into `resolve_columns` because it wasn't selected.
only_load = self.deferred_to_columns()
Expand Down
5 changes: 5 additions & 0 deletions tests/regressiontests/model_fields/models.py
Expand Up @@ -66,6 +66,11 @@ class BooleanModel(models.Model):
bfield = models.BooleanField()
string = models.CharField(max_length=10, default='abc')

class FksToBooleans(models.Model):
"""Model wih FKs to models with {Null,}BooleanField's, #15040"""
bf = models.ForeignKey(BooleanModel)
nbf = models.ForeignKey(NullBooleanModel)

class RenamedField(models.Model):
modelname = models.IntegerField(name="fieldname", choices=((1,'One'),))

Expand Down
40 changes: 39 additions & 1 deletion tests/regressiontests/model_fields/tests.py
Expand Up @@ -12,7 +12,8 @@
from django.utils import unittest

from .models import (Foo, Bar, Whiz, BigD, BigS, Image, BigInt, Post,
NullBooleanModel, BooleanModel, Document, RenamedField, VerboseNameField)
NullBooleanModel, BooleanModel, Document, RenamedField, VerboseNameField,
FksToBooleans)

from .imagefield import (ImageFieldTests, ImageFieldTwoDimensionsTests,
TwoImageFieldTests, ImageFieldNoDimensionsTests,
Expand Down Expand Up @@ -218,6 +219,43 @@ def test_return_type(self):
select={'string_col': 'string'})[0]
self.assertFalse(isinstance(b5.pk, bool))

def test_select_related(self):
"""
Test type of boolean fields when retrieved via select_related() (MySQL,
#15040)
"""
bmt = BooleanModel.objects.create(bfield=True)
bmf = BooleanModel.objects.create(bfield=False)
nbmt = NullBooleanModel.objects.create(nbfield=True)
nbmf = NullBooleanModel.objects.create(nbfield=False)

m1 = FksToBooleans.objects.create(bf=bmt, nbf=nbmt)
m2 = FksToBooleans.objects.create(bf=bmf, nbf=nbmf)

# Test select_related('fk_field_name')
ma = FksToBooleans.objects.select_related('bf').get(pk=m1.id)
# verify types -- should't be 0/1
self.assertIsInstance(ma.bf.bfield, bool)
self.assertIsInstance(ma.nbf.nbfield, bool)
# verify values
self.assertEqual(ma.bf.bfield, True)
self.assertEqual(ma.nbf.nbfield, True)

# Test select_related()
mb = FksToBooleans.objects.select_related().get(pk=m1.id)
mc = FksToBooleans.objects.select_related().get(pk=m2.id)
# verify types -- shouldn't be 0/1
self.assertIsInstance(mb.bf.bfield, bool)
self.assertIsInstance(mb.nbf.nbfield, bool)
self.assertIsInstance(mc.bf.bfield, bool)
self.assertIsInstance(mc.nbf.nbfield, bool)
# verify values
self.assertEqual(mb.bf.bfield, True)
self.assertEqual(mb.nbf.nbfield, True)
self.assertEqual(mc.bf.bfield, False)
self.assertEqual(mc.nbf.nbfield, False)


class ChoicesTests(test.TestCase):
def test_choices_and_field_display(self):
"""
Expand Down

0 comments on commit 142f69e

Please sign in to comment.