Skip to content

Commit e9c24be

Browse files
committed
Fix django#19524 -- Incorrect caching of parents of unsaved model instances.
Thanks qcwxezdas for the report. Refs django#13839.
1 parent 37b3fd2 commit e9c24be

File tree

5 files changed

+48
-4
lines changed

5 files changed

+48
-4
lines changed

django/db/models/base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,15 @@ def save_base(self, raw=False, cls=None, origin=None, force_insert=False,
583583

584584
if field:
585585
setattr(self, field.attname, self._get_pk_val(parent._meta))
586+
# Since we didn't have an instance of the parent handy, we
587+
# set attname directly, bypassing the descriptor.
588+
# Invalidate the related object cache, in case it's been
589+
# accidentally populated. A fresh instance will be
590+
# re-built from the database if necessary.
591+
cache_name = field.get_cache_name()
592+
if hasattr(self, cache_name):
593+
delattr(self, cache_name)
594+
586595
if meta.proxy:
587596
return
588597

django/forms/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,10 @@ def __init__(self, data=None, files=None, instance=None,
692692
self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
693693
if queryset is None:
694694
queryset = self.model._default_manager
695-
qs = queryset.filter(**{self.fk.name: self.instance})
695+
if self.instance.pk:
696+
qs = queryset.filter(**{self.fk.name: self.instance})
697+
else:
698+
qs = queryset.none()
696699
super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
697700
queryset=qs, **kwargs)
698701

tests/regressiontests/admin_inlines/admin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class ChildModel1Inline(admin.TabularInline):
124124
class ChildModel2Inline(admin.StackedInline):
125125
model = ChildModel2
126126

127+
# admin for #19524
128+
class SightingInline(admin.TabularInline):
129+
model = Sighting
127130

128131
site.register(TitleCollection, inlines=[TitleInline])
129132
# Test bug #12561 and #12778
@@ -141,4 +144,5 @@ class ChildModel2Inline(admin.StackedInline):
141144
site.register(Author, AuthorAdmin)
142145
site.register(CapoFamiglia, inlines=[ConsigliereInline, SottoCapoInline])
143146
site.register(ProfileCollection, inlines=[ProfileInline])
144-
site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline])
147+
site.register(ParentModelWithCustomPk, inlines=[ChildModel1Inline, ChildModel2Inline])
148+
site.register(ExtraTerrestrial, inlines=[SightingInline])

tests/regressiontests/admin_inlines/models.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ class Inner4Tabular(models.Model):
9090
dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.")
9191
holder = models.ForeignKey(Holder4)
9292

93-
9493
# Models for #12749
9594

9695
class Person(models.Model):
@@ -133,6 +132,7 @@ class Chapter(models.Model):
133132

134133

135134
# Models for #16838
135+
136136
class CapoFamiglia(models.Model):
137137
name = models.CharField(max_length=100)
138138

@@ -170,6 +170,17 @@ class ChildModel2(models.Model):
170170
def get_absolute_url(self):
171171
return '/child_model2/'
172172

173+
# Models for #19524
174+
175+
class LifeForm(models.Model):
176+
pass
177+
178+
class ExtraTerrestrial(LifeForm):
179+
name = models.CharField(max_length=100)
180+
181+
class Sighting(models.Model):
182+
et = models.ForeignKey(ExtraTerrestrial)
183+
place = models.CharField(max_length=100)
173184

174185
# Other models
175186

tests/regressiontests/admin_inlines/tests.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from .models import (Holder, Inner, Holder2, Inner2, Holder3, Inner3, Person,
1313
OutfitItem, Fashionista, Teacher, Parent, Child, Author, Book, Profile,
1414
ProfileCollection, ParentModelWithCustomPk, ChildModel1, ChildModel2,
15-
Title)
15+
Sighting, Title)
1616

1717

1818
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
@@ -172,6 +172,23 @@ def test_custom_pk_shortcut(self):
172172
self.assertContains(response, child1_shortcut)
173173
self.assertContains(response, child2_shortcut)
174174

175+
def test_create_inlines_on_inherited_model(self):
176+
"""
177+
Ensure that an object can be created with inlines when it inherits
178+
another class. Bug #19524.
179+
"""
180+
data = {
181+
'name': 'Martian',
182+
'sighting_set-TOTAL_FORMS': 1,
183+
'sighting_set-INITIAL_FORMS': 0,
184+
'sighting_set-MAX_NUM_FORMS': 0,
185+
'sighting_set-0-place': 'Zone 51',
186+
'_save': 'Save',
187+
}
188+
response = self.client.post('/admin/admin_inlines/extraterrestrial/add/', data)
189+
self.assertEqual(response.status_code, 302)
190+
self.assertEqual(Sighting.objects.filter(et__name='Martian').count(), 1)
191+
175192

176193
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
177194
class TestInlineMedia(TestCase):

0 commit comments

Comments
 (0)