New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
5 participants
@albertyw
Contributor

albertyw commented Sep 29, 2013

@charettes

View changes

django/db/models/fields/related.py Outdated
if value == '' or value is None:
if value is None:
return None
elif value == '' and not isinstance(self.related_field, CharField):

This comment has been minimized.

@charettes

charettes Sep 30, 2013

Member

I think you should refer to the empty_strings_allowed property of the related field instead of special casing CharField here.

if value is None or (value == '' and not related_field.empty_strings_allowed)

Not sure an extra connection.features.interprets_empty_strings_as_nulls check is also required here since both values will be interpreted as NULL anyway.

This comment has been minimized.

@albertyw

albertyw Oct 1, 2013

Contributor

I changed it to your suggestion (using self.related_field instead of just related_field) in 61f5df9

@bmispelon

View changes

tests/model_fields/models.py Outdated
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 models with {""} #21194"""

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

Nice touch to follow the previous model's docstring, but I think this one should simply be:
Model with FK to a model with a CharField primarey key, #21194

The {Null,}BooleanField of the previous one just means NullBooleanField and BooleanField.

@bmispelon

View changes

tests/model_fields/models.py Outdated
@@ -62,11 +62,18 @@ class BooleanModel(models.Model):
bfield = models.BooleanField(default=None)
string = models.CharField(max_length=10, default='abc')
class CharModel(models.Model):

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

Nitpicky but I'd call it PrimaryKeyCharmodel, just to be more explicit about what it is.

@bmispelon

View changes

tests/model_fields/models.py Outdated
@@ -62,11 +62,18 @@ class BooleanModel(models.Model):
bfield = models.BooleanField(default=None)
string = models.CharField(max_length=10, default='abc')
class CharModel(models.Model):
string = models.CharField(max_length = 10, primary_key=True)

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

Per pep8, this should be max_length=10 (note the lack of whitespace around the equal sign).

@bmispelon

View changes

tests/model_fields/tests.py Outdated
@@ -140,6 +140,18 @@ def test_callable_default(self):
b = Bar.objects.create(b="bcd")
self.assertEqual(b.a, a)
def test_get_db_prep_save(self):

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

Not sure if that's the best name for this test. How about test_empty_string_fk?

@bmispelon

View changes

tests/model_fields/tests.py Outdated
def test_get_db_prep_save(self):
"""
Test that foreign key values to empty strings don't get converted
to None

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

Make sure you reference your ticket number in the docstring (see the other tests in the file).

@bmispelon

View changes

tests/model_fields/tests.py Outdated
to None
"""
char_model_normal = CharModel.objects.create(string='asdf')
fk_model_normal = FkToChar.objects.create(out=char_model_normal)

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

I don't think the two lines (*_normal) are needed here since this functionality is most likely tested elsewhere (and you don't make use of those variables in your assertions later on).

This comment has been minimized.

@albertyw

albertyw Oct 2, 2013

Contributor

I did look for tests that used the get_db_prep_save method, but I didn't find any. Agreed, I should actually write an assertion for the normal case, assuming it isn't covered somewhere else.

This comment has been minimized.

@albertyw

albertyw Oct 2, 2013

Contributor

I just removed the normal case lines because I'm guessing it is covered somewhere else and I just didn't see it. If it isn't covered, it would be outside the scope of this pull request/ticket 21194

@bmispelon

View changes

tests/model_fields/tests.py Outdated
char_model_normal = CharModel.objects.create(string='asdf')
fk_model_normal = FkToChar.objects.create(out=char_model_normal)
char_model_empty = CharModel.objects.create(string='')
fk_model_empty = FkToChar.objects.create(out=char_model_empty)

This comment has been minimized.

@bmispelon

bmispelon Oct 2, 2013

Member

You don't need to assign the result to a variable here.

This comment has been minimized.

@albertyw

albertyw Oct 2, 2013

Contributor

I do need the pk of the newly created FkToChar model to lookup (and reload) the same object again on the next line.

@shaib

View changes

tests/model_fields/tests.py Outdated
@@ -141,6 +141,15 @@ def test_callable_default(self):
b = Bar.objects.create(b="bcd")
self.assertEqual(b.a, a)
def test_empty_string_fk(self):

This comment has been minimized.

@shaib

shaib Nov 25, 2013

Member

This test needs to be made to pass or skip when the connection interprets_empty_strings_as_null -- skipIfDBFeature is your friend
(on Oracle, line 149 will raise an IntegrityError).

@shaib

View changes

tests/model_fields/models.py Outdated
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, #21194"""

This comment has been minimized.

@shaib

shaib Nov 25, 2013

Member

Since 21194 was closed as a dupe, you may want to update the references to 19299.

@timgraham

View changes

django/db/models/query.py Outdated
# 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 \

This comment has been minimized.

@timgraham

timgraham Feb 8, 2014

Member

Prefer wrapping the expression in parentheses rather than using a backslash

@timgraham

View changes

django/db/models/fields/related.py Outdated
@@ -1320,7 +1321,7 @@ def get_default(self):
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)):

This comment has been minimized.

@timgraham

timgraham Feb 8, 2014

Member

break this into multiple lines?

@timgraham

This comment has been minimized.

Member

timgraham commented Feb 8, 2014

Could you please rebase the patch to apply cleanly?

@timgraham

View changes

django/db/models/fields/related.py Outdated
@@ -7,7 +7,8 @@
from django.db.models import signals, Q
from django.db.models.deletion import SET_NULL, SET_DEFAULT, CASCADE
from django.db.models.fields import (AutoField, Field, IntegerField,
PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist)
PositiveIntegerField, PositiveSmallIntegerField, FieldDoesNotExist,
CharField)

This comment has been minimized.

@timgraham

timgraham Feb 13, 2014

Member

unused import (please check code with flake8 as there are some "expected 2 blank lines" warnings as well).

# 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

This comment has been minimized.

@timgraham

timgraham Feb 13, 2014

Member

Could you add a test for this change? If I revert it I don't get any test failures.

This comment has been minimized.

@albertyw

albertyw Feb 14, 2014

Contributor

There is a test for it. See https://github.com/django/django/pull/1690/files#diff-e4aa8dc49d7522ae55a932ffc7d09c1cR149

Are you running your tests only on databases that interpret empty strings as null values?

This comment has been minimized.

@timgraham

timgraham Feb 14, 2014

Member

I'm trying on SQLite and the new test isn't skipped. If I revert the changes in django/db/models/fields/related.py it fails, but if I revert the change in this file, it still passes.

This comment has been minimized.

@albertyw

albertyw Feb 15, 2014

Contributor

I see what you mean. I changed tests/model_fields/tests.py:157 so that it would raise an error.

@timgraham

This comment has been minimized.

Member

timgraham commented Feb 15, 2014

Great, merged in 8bbdcc7, thank-you.

@timgraham timgraham closed this Feb 15, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment