Fixed #26179 -- Removed null assignment check for non-nullable foreign key fields.
This commit is contained in:
parent
353aecbf8c
commit
04e13c8913
|
@ -193,14 +193,8 @@ class ForwardManyToOneDescriptor(object):
|
|||
- ``instance`` is the ``child`` instance
|
||||
- ``value`` in the ``parent`` instance on the right of the equal sign
|
||||
"""
|
||||
# If null=True, we can assign null here, but otherwise the value needs
|
||||
# to be an instance of the related class.
|
||||
if value is None and self.field.null is False:
|
||||
raise ValueError(
|
||||
'Cannot assign None: "%s.%s" does not allow null values.' %
|
||||
(instance._meta.object_name, self.field.name)
|
||||
)
|
||||
elif value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model):
|
||||
# An object must be an instance of the related class.
|
||||
if value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model):
|
||||
raise ValueError(
|
||||
'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
|
||||
value,
|
||||
|
@ -379,26 +373,17 @@ class ReverseOneToOneDescriptor(object):
|
|||
# ForwardManyToOneDescriptor is annoying, but there's a bunch
|
||||
# of small differences that would make a common base class convoluted.
|
||||
|
||||
# If null=True, we can assign null here, but otherwise the value needs
|
||||
# to be an instance of the related class.
|
||||
if value is None:
|
||||
if self.related.field.null:
|
||||
# Update the cached related instance (if any) & clear the cache.
|
||||
try:
|
||||
rel_obj = getattr(instance, self.cache_name)
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
delattr(instance, self.cache_name)
|
||||
setattr(rel_obj, self.related.field.name, None)
|
||||
# Update the cached related instance (if any) & clear the cache.
|
||||
try:
|
||||
rel_obj = getattr(instance, self.cache_name)
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
raise ValueError(
|
||||
'Cannot assign None: "%s.%s" does not allow null values.' % (
|
||||
instance._meta.object_name,
|
||||
self.related.get_accessor_name(),
|
||||
)
|
||||
)
|
||||
delattr(instance, self.cache_name)
|
||||
setattr(rel_obj, self.related.field.name, None)
|
||||
elif not isinstance(value, self.related.related_model):
|
||||
# An object must be an instance of the related class.
|
||||
raise ValueError(
|
||||
'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
|
||||
value,
|
||||
|
|
|
@ -479,6 +479,14 @@ creates the possibility of a deadlock. To adapt your code in the case of RQ,
|
|||
you can `provide your own worker script <http://python-rq.org/docs/workers/>`_
|
||||
that calls ``django.setup()``.
|
||||
|
||||
Removed null assignment check for non-null foreign key fields
|
||||
-------------------------------------------------------------
|
||||
|
||||
In older versions, assigning ``None`` to a non-nullable ``ForeignKey`` or
|
||||
``OneToOneField`` raised ``ValueError('Cannot assign None: "model.field" does
|
||||
not allow null values.')``. For consistency with other model fields which don't
|
||||
have a similar check, this check is removed.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
|
|
|
@ -717,14 +717,11 @@ class ProxyRelatedModelTest(TestCase):
|
|||
|
||||
|
||||
class TestInitWithNoneArgument(SimpleTestCase):
|
||||
def test_none_not_allowed(self):
|
||||
# TaggedItem requires a content_type, initializing with None should
|
||||
# raise a ValueError.
|
||||
msg = 'Cannot assign None: "TaggedItem.content_type" does not allow null values'
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
TaggedItem(content_object=None)
|
||||
|
||||
def test_none_allowed(self):
|
||||
# AllowsNullGFK doesn't require a content_type, so None argument should
|
||||
# also be allowed.
|
||||
AllowsNullGFK(content_object=None)
|
||||
# TaggedItem requires a content_type but initializing with None should
|
||||
# be allowed.
|
||||
TaggedItem(content_object=None)
|
||||
|
|
|
@ -3,6 +3,7 @@ from copy import deepcopy
|
|||
|
||||
from django.core.exceptions import FieldError, MultipleObjectsReturned
|
||||
from django.db import models, transaction
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
|
@ -486,19 +487,19 @@ class ManyToOneTests(TestCase):
|
|||
p = Parent.objects.get(name="Parent")
|
||||
self.assertIsNone(p.bestchild)
|
||||
|
||||
# Assigning None fails: Child.parent is null=False.
|
||||
with self.assertRaises(ValueError):
|
||||
setattr(c, "parent", None)
|
||||
# Assigning None will not fail: Child.parent is null=False.
|
||||
setattr(c, "parent", None)
|
||||
|
||||
# You also can't assign an object of the wrong type here
|
||||
with self.assertRaises(ValueError):
|
||||
setattr(c, "parent", First(id=1, second=1))
|
||||
|
||||
# Nor can you explicitly assign None to Child.parent during object
|
||||
# creation (regression for #9649).
|
||||
with self.assertRaises(ValueError):
|
||||
Child(name='xyzzy', parent=None)
|
||||
with self.assertRaises(ValueError):
|
||||
# You can assign None to Child.parent during object creation.
|
||||
Child(name='xyzzy', parent=None)
|
||||
|
||||
# But when trying to save a Child with parent=None, the database will
|
||||
# raise IntegrityError.
|
||||
with self.assertRaises(IntegrityError), transaction.atomic():
|
||||
Child.objects.create(name='xyzzy', parent=None)
|
||||
|
||||
# Creation using keyword argument should cache the related object.
|
||||
|
|
|
@ -228,9 +228,8 @@ class OneToOneTests(TestCase):
|
|||
ug_bar.place = None
|
||||
self.assertIsNone(ug_bar.place)
|
||||
|
||||
# Assigning None fails: Place.restaurant is null=False
|
||||
with self.assertRaises(ValueError):
|
||||
setattr(p, 'restaurant', None)
|
||||
# Assigning None will not fail: Place.restaurant is null=False
|
||||
setattr(p, 'restaurant', None)
|
||||
|
||||
# You also can't assign an object of the wrong type here
|
||||
with self.assertRaises(ValueError):
|
||||
|
|
Loading…
Reference in New Issue