Commit 819e09b8 authored by Daniel Pyrathon's avatar Daniel Pyrathon Committed by Marc Tamlyn
Browse files

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.
parent 3bd45ba0
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -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'):
                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)

+4 −0
Original line number Diff line number Diff line
@@ -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
^^^^^^^

+3 −0
Original line number Diff line number Diff line
@@ -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)
+11 −1
Original line number Diff line number Diff line
@@ -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')]