summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Pyrathon <pirosb3@gmail.com>2014-03-10 15:17:57 +0000
committerMarc Tamlyn <marc.tamlyn@gmail.com>2014-03-10 15:25:18 +0000
commit819e09b848e4f1cc45165a99ffbef1307b215a08 (patch)
treeb424ef7353b1cdaeb60adf166606bc05357b3acc
parent3bd45ba00d0f43e9ea192eca132624b30cae4eee (diff)
Fixed #22210 -- Saving model instances to non-related fields.
Previously, saving a model instance to a non-related field (in particular a FloatField) would silently convert the model to an Integer (the pk) and save it. This is undesirable behaviour, and likely to cause confusion so the validatio has been hardened. Thanks to @PirosB3 for the patch and @jarshwah for the review.
-rw-r--r--django/db/models/sql/compiler.py10
-rw-r--r--docs/releases/1.7.txt4
-rw-r--r--tests/model_fields/models.py3
-rw-r--r--tests/model_fields/tests.py12
4 files changed, 27 insertions, 2 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 11c503cd5d..5636f344df 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -4,6 +4,7 @@ from django.conf import settings
from django.core.exceptions import FieldError
from django.db.backends.utils import truncate_name
from django.db.models.constants import LOOKUP_SEP
+from django.db.models.expressions import ExpressionNode
from django.db.models.query_utils import select_related_descend, QueryWrapper
from django.db.models.sql.constants import (CURSOR, SINGLE, MULTI, NO_RESULTS,
ORDER_DIR, GET_ITERATOR_CHUNK_SIZE, SelectInfo)
@@ -951,7 +952,14 @@ class SQLUpdateCompiler(SQLCompiler):
values, update_params = [], []
for field, model, val in self.query.values:
if hasattr(val, 'prepare_database_save'):
- val = val.prepare_database_save(field)
+ if field.rel or isinstance(val, ExpressionNode):
+ val = val.prepare_database_save(field)
+ else:
+ raise TypeError("Database is trying to update a relational field "
+ "of type %s with a value of type %s. Make sure "
+ "you are setting the correct relations" %
+ (field.__class__.__name__,
+ val.__class__.__name__))
else:
val = field.get_db_prep_save(val, connection=self.connection)
diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
index 52007c98aa..2dd3931060 100644
--- a/docs/releases/1.7.txt
+++ b/docs/releases/1.7.txt
@@ -674,6 +674,10 @@ Models
the new :attr:`ManyToManyField.through_fields <django.db.models.ManyToManyField.through_fields>`
argument.
+* Assigning a model instance to a non-relation field will now throw an error.
+ Previously this used to work if the field accepted integers as input as it
+ took the primary key.
+
Signals
^^^^^^^
diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py
index e110578ce9..b16287a66c 100644
--- a/tests/model_fields/models.py
+++ b/tests/model_fields/models.py
@@ -48,6 +48,9 @@ class Whiz(models.Model):
class BigD(models.Model):
d = models.DecimalField(max_digits=38, decimal_places=30)
+class FloatModel(models.Model):
+ size = models.FloatField()
+
class BigS(models.Model):
s = models.SlugField(max_length=255)
diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py
index 194219a114..a39ad81f64 100644
--- a/tests/model_fields/tests.py
+++ b/tests/model_fields/tests.py
@@ -23,7 +23,7 @@ from django.utils.functional import lazy
from .models import (
Foo, Bar, Whiz, BigD, BigS, BigInt, Post, NullBooleanModel,
BooleanModel, PrimaryKeyCharModel, DataModel, Document, RenamedField,
- VerboseNameField, FksToBooleans, FkToChar)
+ VerboseNameField, FksToBooleans, FkToChar, FloatModel)
class BasicFieldTests(test.TestCase):
@@ -78,6 +78,16 @@ class BasicFieldTests(test.TestCase):
self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk')
+ def test_float_validates_object(self):
+ instance = FloatModel(size=2.5)
+ instance.save()
+ self.assertTrue(instance.id)
+
+ obj = FloatModel.objects.get(pk=1)
+ obj.size = obj
+ with self.assertRaises(TypeError):
+ obj.save()
+
def test_choices_form_class(self):
"""Can supply a custom choices form class. Regression for #20999."""
choices = [('a', 'a')]