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.
This commit is contained in:
parent
2b916895a1
commit
04d9730b12
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue