summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRamiro Morales <cramm0@gmail.com>2013-02-05 23:35:10 -0300
committerRamiro Morales <cramm0@gmail.com>2013-02-07 16:05:54 -0300
commit04d9730b127c689b8eda01cbc913efa6e2eb230b (patch)
tree5ff07b85c9a3b5e192fc9abfb537701d30593fd7
parent2b916895a1cea39de3280a6910e2886aebfcfc64 (diff)
Fixed #13085 -- Don't fail on creation of model with GFK to a model with __len__() returning zero.
Also, according to the comments on the ticket and its duplicates, added tests execising saving an instance of a model with a GFK to: * An unsaved object -- This actually doesn't generate the same failure but another ORM-level exception. The test verifies it's the case. * An instance of a model with a __nonzero__() method thant returns False for it. This doesn't fail because that code path isn't executed. * An instance of a model with a CharField PK and an empty value for it. This doesn't fail.
-rw-r--r--django/contrib/contenttypes/generic.py4
-rw-r--r--tests/regressiontests/generic_relations_regress/models.py31
-rw-r--r--tests/regressiontests/generic_relations_regress/tests.py40
3 files changed, 72 insertions, 3 deletions
diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py
index d849d1607e..20ff7042bc 100644
--- a/django/contrib/contenttypes/generic.py
+++ b/django/contrib/contenttypes/generic.py
@@ -43,7 +43,7 @@ class GenericForeignKey(object):
def instance_pre_init(self, signal, sender, args, kwargs, **_kwargs):
"""
- Handles initializing an object with the generic FK instaed of
+ Handles initializing an object with the generic FK instead of
content-type/object-id fields.
"""
if self.name in kwargs:
@@ -52,7 +52,7 @@ class GenericForeignKey(object):
kwargs[self.fk_field] = value._get_pk_val()
def get_content_type(self, obj=None, id=None, using=None):
- if obj:
+ if obj is not None:
return ContentType.objects.db_manager(obj._state.db).get_for_model(obj)
elif id:
return ContentType.objects.db_manager(using).get_for_id(id)
diff --git a/tests/regressiontests/generic_relations_regress/models.py b/tests/regressiontests/generic_relations_regress/models.py
index bdd8ec5eda..2795471f7f 100644
--- a/tests/regressiontests/generic_relations_regress/models.py
+++ b/tests/regressiontests/generic_relations_regress/models.py
@@ -91,3 +91,34 @@ class Company(models.Model):
def __str__(self):
return "Company: %s" % self.name
+
+# For testing #13085 fix, we also use Note model defined above
+class Developer(models.Model):
+ name = models.CharField(max_length=15)
+
+@python_2_unicode_compatible
+class Team(models.Model):
+ name = models.CharField(max_length=15)
+ members = models.ManyToManyField(Developer)
+
+ def __str__(self):
+ return "%s team" % self.name
+
+ def __len__(self):
+ return self.members.count()
+
+class Guild(models.Model):
+ name = models.CharField(max_length=15)
+ members = models.ManyToManyField(Developer)
+
+ def __nonzero__(self):
+ return self.members.count()
+
+class Tag(models.Model):
+ content_type = models.ForeignKey(ContentType, related_name='g_r_r_tags')
+ object_id = models.CharField(max_length=15)
+ content_object = generic.GenericForeignKey()
+ label = models.CharField(max_length=15)
+
+class Board(models.Model):
+ name = models.CharField(primary_key=True, max_length=15)
diff --git a/tests/regressiontests/generic_relations_regress/tests.py b/tests/regressiontests/generic_relations_regress/tests.py
index 9aa3268fe2..b53129aa12 100644
--- a/tests/regressiontests/generic_relations_regress/tests.py
+++ b/tests/regressiontests/generic_relations_regress/tests.py
@@ -1,8 +1,10 @@
from django.db.models import Q
+from django.db.utils import IntegrityError
from django.test import TestCase
from .models import (Address, Place, Restaurant, Link, CharLink, TextLink,
- Person, Contact, Note, Organization, OddRelation1, OddRelation2, Company)
+ Person, Contact, Note, Organization, OddRelation1, OddRelation2, Company,
+ Developer, Team, Guild, Tag, Board)
class GenericRelationTests(TestCase):
@@ -98,3 +100,39 @@ class GenericRelationTests(TestCase):
self.assertEqual(len(places), 2)
self.assertEqual(count_places(p1), 1)
self.assertEqual(count_places(p2), 1)
+
+ def test_target_model_is_unsaved(self):
+ """Test related to #13085"""
+ # Fails with another, ORM-level error
+ dev1 = Developer(name='Joe')
+ note = Note(note='Deserves promotion', content_object=dev1)
+ self.assertRaisesMessage(IntegrityError,
+ "generic_relations_regress_note.object_id may not be NULL",
+ note.save)
+
+ def test_target_model_len_zero(self):
+ """Test for #13085 -- __len__() returns 0"""
+ team1 = Team.objects.create(name='Backend devs')
+ try:
+ note = Note(note='Deserve a bonus', content_object=team1)
+ except Exception as e:
+ if issubclass(type(e), Exception) and str(e) == 'Impossible arguments to GFK.get_content_type!':
+ self.fail("Saving model with GenericForeignKey to model instance whose __len__ method returns 0 shouldn't fail.")
+ raise e
+ note.save()
+
+ def test_target_model_nonzero_false(self):
+ """Test related to #13085"""
+ # __nonzero__() returns False -- This actually doesn't currently fail.
+ # This test validates that
+ g1 = Guild.objects.create(name='First guild')
+ note = Note(note='Note for guild', content_object=g1)
+ note.save()
+
+ def test_gfk_to_model_with_empty_pk(self):
+ """Test related to #13085"""
+ # Saving model with GenericForeignKey to model instance with an
+ # empty CharField PK
+ b1 = Board.objects.create(name='')
+ tag = Tag(label='VP', content_object=b1)
+ tag.save()