Commit 8bbdcc76 authored by Albert Wang's avatar Albert Wang Committed by Tim Graham
Browse files

Fixed #19299 -- Fixed Nullification of Foreign Keys To CharFields

Thanks tunixman for the report and Baptiste Mispelon and
Shai Berger for reviews.
parent 4d4e0ea4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -646,6 +646,7 @@ answer newbie questions, and generally made Django that much better:
    Rick Wagner <rwagner@physics.ucsd.edu>
    Gavin Wahl <gavinwahl@gmail.com>
    wam-djangobug@wamber.net
    Albert Wang <aywang31@gmail.com>
    Wang Chun <wangchun@exoweb.net>
    Filip Wasilewski <filip.wasilewski@gmail.com>
    Dan Watson <http://danwatson.net/>
+4 −3
Original line number Diff line number Diff line
@@ -1692,11 +1692,12 @@ class ForeignKey(ForeignObject):
        return field_default

    def get_db_prep_save(self, value, connection):
        if value == '' or value is None:
        if value is None or (value == '' and
                             (not self.related_field.empty_strings_allowed or
                              connection.features.interprets_empty_strings_as_nulls)):
            return None
        else:
            return self.related_field.get_db_prep_save(value,
                connection=connection)
            return self.related_field.get_db_prep_save(value, connection=connection)

    def value_to_string(self, obj):
        if not obj:
+5 −2
Original line number Diff line number Diff line
@@ -1416,9 +1416,12 @@ def get_cached_row(row, index_start, using, klass_info, offset=0,
    klass, field_names, field_count, related_fields, reverse_related_fields, pk_idx = klass_info

    fields = row[index_start:index_start + field_count]
    # If the pk column is None (or the Oracle equivalent ''), then the related
    # If the pk column is None (or the equivalent '' in the case the
    # connection interprets empty strings as nulls), then the related
    # object must be non-existent - set the relation to None.
    if fields[pk_idx] is None or fields[pk_idx] == '':
    if (fields[pk_idx] is None or
        (connections[using].features.interprets_empty_strings_as_nulls and
         fields[pk_idx] == '')):
        obj = None
    elif field_names:
        fields = list(fields)
+9 −0
Original line number Diff line number Diff line
@@ -72,12 +72,21 @@ class BooleanModel(models.Model):
    string = models.CharField(max_length=10, default='abc')


class PrimaryKeyCharModel(models.Model):
    string = models.CharField(max_length=10, primary_key=True)


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


class FkToChar(models.Model):
    """Model with FK to a model with a CharField primary key, #19299"""
    out = models.ForeignKey(PrimaryKeyCharModel)


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

+13 −2
Original line number Diff line number Diff line
@@ -22,8 +22,8 @@ from django.utils.functional import lazy

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


class BasicFieldTests(test.TestCase):
@@ -146,6 +146,17 @@ class ForeignKeyTests(test.TestCase):
        b = Bar.objects.create(b="bcd")
        self.assertEqual(b.a, a)

    @test.skipIfDBFeature('interprets_empty_strings_as_nulls')
    def test_empty_string_fk(self):
        """
        Test that foreign key values to empty strings don't get converted
        to None (#19299)
        """
        char_model_empty = PrimaryKeyCharModel.objects.create(string='')
        fk_model_empty = FkToChar.objects.create(out=char_model_empty)
        fk_model_empty = FkToChar.objects.select_related('out').get(id=fk_model_empty.pk)
        self.assertEqual(fk_model_empty.out, char_model_empty)


class DateTimeFieldTests(unittest.TestCase):
    def test_datetimefield_to_python_usecs(self):