Ticket #11811: 11811-patch-rev-5.diff
File 11811-patch-rev-5.diff, 7.2 KB (added by , 15 years ago) |
---|
-
django/db/models/base.py
638 638 return getattr(self, cachename) 639 639 640 640 def prepare_database_save(self, unused): 641 if self.pk is None: 642 # This is reached if this instance is missing a primary key value 643 # but is passed as a parameter to a queryset's update() method, 644 # which needs some value to use as a foreign key. 645 raise ValueError('Cannot assign the instance "%r" to a foreign key' 646 ' field, because its primary key is not available.' 647 ' (For autonumbered keys, the instance would need to be saved' 648 ' first.)' % self) 641 649 return self.pk 642 650 643 651 def clean(self): -
django/db/models/fields/related.py
807 807 if isinstance(field_default, self.rel.to): 808 808 return getattr(field_default, self.rel.get_related_field().attname) 809 809 return field_default 810 811 def pre_save(self, model_instance, add): 812 value = super(ForeignKey, self).pre_save(model_instance, add) 813 if (value is None and self.null and 814 getattr(model_instance, self.get_cache_name(), None) is not None): 815 # Error: we don't have a related key to save but do have a cached 816 # related instance. This indicates that a reference to the related 817 # instance was intended to make it into the database, but the lack 818 # of a related key value at the time of assignment makes this 819 # impossible. 820 # The situation is typically caused by assigning a new, unsaved 821 # instance to a foreign key field, leaving its autonumbered 822 # primary key empty. 823 # Non-null fields will raise an exception in this case anyway 824 # (an IntegrityError) so we only worry about nullable fields, 825 # to preserve previous behavior. 826 raise ValueError('Cannot save a foreign key referring to the' 827 ' instance "%r" into the field "%s.%s", because the key value' 828 ' for the instance was not available at the time of assignment' 829 ' to the field. (For autonumbered keys, the related instance' 830 ' may need to be saved prior to the assignment.)' % 831 (getattr(model_instance, self.get_cache_name()), 832 model_instance._meta.object_name, self.name)) 833 return value 810 834 811 835 def get_db_prep_save(self, value, connection): 812 836 if value == '' or value == None: -
tests/regressiontests/model_regress/tests.py
1 from models import Worker 1 from models import Department, Worker, Site, Flatpage 2 from django.core.exceptions import ObjectDoesNotExist 2 3 from django.test import TestCase 3 4 4 5 class RelatedModelOrderedLookupTest(TestCase): … … 14 15 15 16 def test_related_lte_lookup(self): 16 17 Worker.objects.filter(department__lte=0) 18 19 class AssignmentWithMissingForeignKeyTest(TestCase): 20 """ 21 Regression test for #11811: setting a foreign key field to a model 22 instance with a null pk (i.e. an unsaved instance) should raise an 23 exception, which occurs when the model is saved to the database. 24 """ 25 def test_attr_assignment_nullable(self): 26 s = Site(name='My Unsaved Site') 27 f = Flatpage(id=1, text='I will try to specify that site') 28 f.site = s 29 self.assertRaises(ValueError, f.save) 30 self.assertRaises(ObjectDoesNotExist, lambda: Flatpage.objects.get( 31 id=1)) 32 33 def test_model_initializer_nullable(self): 34 s = Site(name='My Unsaved Site') 35 f = Flatpage(id=2, text='I will also try to specify that site', site=s) 36 self.assertRaises(ValueError, f.save) 37 self.assertRaises(ObjectDoesNotExist, lambda: Flatpage.objects.get( 38 id=2)) 39 40 def test_manager_create_nullable(self): 41 s = Site(name='My Unsaved Site') 42 self.assertRaises(ValueError, lambda: Flatpage.objects.create(id=3, 43 text='Never mind, I will try to specify that site', site=s)) 44 self.assertRaises(ObjectDoesNotExist, lambda: Flatpage.objects.get( 45 id=3)) 46 47 def test_queryset_update_nullable(self): 48 s = Site(name='My Unsaved Site') 49 Flatpage.objects.create(id=4, text='Not specifying a site') 50 self.assertRaises(ValueError, lambda: Flatpage.objects.filter( 51 id=4).update(site=s)) 52 53 def test_attr_assignment_nonnull(self): 54 d = Department(name='An Unsaved Department') 55 w = Worker(id=1, name='Milton Waddams') 56 w.department = d 57 # the DB backend will define its own IntegrityError, so 58 # catch Exception to be backend-neutral 59 self.assertRaises(Exception, w.save) 60 self.assertRaises(ObjectDoesNotExist, lambda: Worker.objects.get( 61 id=1)) 62 63 def test_model_initializer_nonnull(self): 64 d = Department(name='An Unsaved Department') 65 w = Worker(id=2, name='Milton Waddams', department=d) 66 # the DB backend will define its own IntegrityError, so 67 # catch Exception to be backend-neutral 68 self.assertRaises(Exception, w.save) 69 self.assertRaises(ObjectDoesNotExist, lambda: Worker.objects.get( 70 id=2)) 71 72 def test_manager_create_nonnull(self): 73 d = Department(name='An Unsaved Department') 74 # the DB backend will define its own IntegrityError, so 75 # catch Exception to be backend-neutral 76 self.assertRaises(Exception, lambda: Worker.objects.create(id=3, 77 name='Milton Waddams', department=d)) 78 self.assertRaises(ObjectDoesNotExist, lambda: Worker.objects.get( 79 id=3)) 80 81 def test_queryset_update_nonnull(self): 82 d1 = Department(id=1, name='A Real Department') 83 d1.save() 84 d2 = Department(name='An Unsaved Department') 85 Worker.objects.create(id=4, name='Milton Waddams', department=d1) 86 self.assertRaises(ValueError, lambda: Worker.objects.filter( 87 id=4).update(department=d2)) 88 -
tests/regressiontests/model_regress/models.py
50 50 def __unicode__(self): 51 51 return self.name 52 52 53 # two models with a nullable foreign key relationship for testing #11811 54 class Site(models.Model): 55 name = models.CharField(max_length=200) 56 57 def __unicode__(self): 58 return self.name 59 60 class Flatpage(models.Model): 61 text = models.TextField() 62 site = models.ForeignKey(Site, null=True) 63 53 64 class BrokenUnicodeMethod(models.Model): 54 65 name = models.CharField(max_length=7) 55 66