Skip to content

Commit

Permalink
Don't automatically collapse '' and None for keys.
Browse files Browse the repository at this point in the history
Many databases treat these differently, including MySQL, and there are
legitimate cases where `''` is a valid value in key fields. This change
updates both the ForeignKey class and the row cache to check the
connection feature `interprets_empty_strings_as_nulls` and will collapse
these two values if that's `True`, otherwise it will treat them
differently.
  • Loading branch information
Evan Cofsky committed Nov 16, 2012
1 parent 7cfb567 commit 386ef64
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 4 deletions.
4 changes: 3 additions & 1 deletion django/db/models/fields/related.py
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,9 @@ def get_default(self):
return field_default

def get_db_prep_save(self, value, connection):
if value == '' or value == None:
if (value == None or
(connection.features.interprets_empty_strings_as_nulls
and value == '')):
return None
else:
return self.rel.get_related_field().get_db_prep_save(value,
Expand Down
7 changes: 5 additions & 2 deletions django/db/models/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -1441,9 +1441,12 @@ def get_cached_row(row, index_start, using, klass_info, offset=0,


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] == None or fields[pk_idx] == '':
if (fields[pk_idx] == None or
(connections[using].features.interprets_empty_strings_as_nulls
and fields[pk_idx] == '')):
obj = None
elif field_names:
fields = list(fields)
Expand Down
7 changes: 7 additions & 0 deletions tests/modeltests/model_forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,10 @@ class FlexibleDatePost(models.Model):
slug = models.CharField(max_length=50, unique_for_year='posted', blank=True)
subtitle = models.CharField(max_length=50, unique_for_month='posted', blank=True)
posted = models.DateField(blank=True, null=True)

class EmptyKeySource(models.Model):
name = models.CharField(max_length=50, unique=True, null=False, blank=True, db_index=True)

class EmptyKeySink(models.Model):
title = models.CharField(max_length=50, unique=True, null=False, blank=True, db_index=True)
source = models.ForeignKey(EmptyKeySource, to_field='name', blank=True, null=False)
12 changes: 11 additions & 1 deletion tests/modeltests/model_forms/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
Category, CommaSeparatedInteger, CustomFieldForExclusionModel, DerivedBook,
DerivedPost, ExplicitPK, FlexibleDatePost, ImprovedArticle,
ImprovedArticleWithParentLink, Inventory, PhoneNumber, Post, Price,
Product, TextFile, Writer, WriterProfile, test_images)
Product, TextFile, Writer, WriterProfile, test_images,
EmptyKeySource, EmptyKeySink)

if test_images:
from .models import ImageFile, OptionalImageFile
Expand Down Expand Up @@ -1524,3 +1525,12 @@ def test_model_field_that_returns_none_to_exclude_itself_with_explicit_fields(se
['name'])
self.assertHTMLEqual(six.text_type(CustomFieldForExclusionForm()),
'''<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="10" /></td></tr>''')

def test_foreignkeys_which_use_to_field_and_blank_string_key(self):
source_n = EmptyKeySource.objects.create(name="")
source_a = EmptyKeySource.objects.create(name="a")
source_b = EmptyKeySource.objects.create(name="b")

sink_n = EmptyKeySink.objects.create(title="Hello", source=source_n)

self.assertEqual(sink_n.source, source_n)

0 comments on commit 386ef64

Please sign in to comment.