From 3918eeb9fde03a2ad1941bce022615fff8eae34d Mon Sep 17 00:00:00 2001 From: Bouke Haarsma Date: Tue, 15 Oct 2013 17:24:35 +0200 Subject: [PATCH] Fixed #7551 -- Made GFK allow None init argument. Thanks SamBull for the report. --- django/contrib/contenttypes/generic.py | 8 ++++++-- tests/generic_relations/models.py | 7 +++++++ tests/generic_relations/tests.py | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index 51eed3f28b..241f497590 100644 --- a/django/contrib/contenttypes/generic.py +++ b/django/contrib/contenttypes/generic.py @@ -59,8 +59,12 @@ class GenericForeignKey(six.with_metaclass(RenameGenericForeignKeyMethods)): """ if self.name in kwargs: value = kwargs.pop(self.name) - kwargs[self.ct_field] = self.get_content_type(obj=value) - kwargs[self.fk_field] = value._get_pk_val() + if value is not None: + kwargs[self.ct_field] = self.get_content_type(obj=value) + kwargs[self.fk_field] = value._get_pk_val() + else: + kwargs[self.ct_field] = None + kwargs[self.fk_field] = None def get_content_type(self, obj=None, id=None, using=None): if obj is not None: diff --git a/tests/generic_relations/models.py b/tests/generic_relations/models.py index 79eb59fe47..859a17845e 100644 --- a/tests/generic_relations/models.py +++ b/tests/generic_relations/models.py @@ -137,3 +137,10 @@ class ConcreteRelatedModel(models.Model): class ProxyRelatedModel(ConcreteRelatedModel): class Meta: proxy = True + + +# To test fix for #7551 +class AllowsNullGFK(models.Model): + content_type = models.ForeignKey(ContentType, null=True) + object_id = models.PositiveIntegerField(null=True) + content_object = generic.GenericForeignKey() diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index dde00ccc8a..6f3f267c5f 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -4,11 +4,12 @@ from django import forms from django.contrib.contenttypes.generic import generic_inlineformset_factory from django.contrib.contenttypes.models import ContentType from django.test import TestCase +from django.utils import six from .models import (TaggedItem, ValuableTaggedItem, Comparison, Animal, Vegetable, Mineral, Gecko, Rock, ManualPK, ForProxyModelModel, ForConcreteModelModel, - ProxyRelatedModel, ConcreteRelatedModel) + ProxyRelatedModel, ConcreteRelatedModel, AllowsNullGFK) class GenericRelationsTests(TestCase): @@ -440,3 +441,17 @@ class ProxyRelatedModelTest(TestCase): newrel.bases = [base] newrel = ConcreteRelatedModel.objects.get(pk=newrel.pk) self.assertEqual(base, newrel.bases.get()) + + +class TestInitWithNoneArgument(TestCase): + def test_none_not_allowed(self): + # TaggedItem requires a content_type, initializing with None should + # raise a ValueError. + with six.assertRaisesRegex(self, ValueError, + 'Cannot assign None: "TaggedItem.content_type" does not allow null values'): + 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)