Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #12749 -- Corrected a problem with validation of inline primary…

… keys. Thanks to Chris.Wesseling@cwi.nl for the report, and nessita for the test case.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13034 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit dd07c235454baea0c74fa373cc07187942f3aed0 1 parent b031fa2
Russell Keith-Magee authored April 27, 2010
7  django/db/models/fields/related.py
@@ -824,13 +824,8 @@ def __init__(self, to, to_field=None, rel_class=ManyToOneRel, **kwargs):
16  django/forms/models.py
@@ -316,12 +316,23 @@ def clean(self):
316 316
         return self.cleaned_data
317 317
 
318 318
     def _post_clean(self):
319  
-        exclude = self._get_validation_exclusions()
320 319
         opts = self._meta
321  
-
322 320
         # Update the model instance with self.cleaned_data.
323 321
         self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
324 322
 
  323
+        exclude = self._get_validation_exclusions()
  324
+
  325
+        # Foreign Keys being used to represent inline relationships
  326
+        # are excluded from basic field value validation. This is for two
  327
+        # reasons: firstly, the value may not be supplied (#12507; the
  328
+        # case of providing new values to the admin); secondly the
  329
+        # object being referred to may not yet fully exist (#12749).
  330
+        # However, these fields *must* be included in uniqueness checks,
  331
+        # so this can't be part of _get_validation_exclusions().
  332
+        for f_name, field in self.fields.items():
  333
+            if isinstance(field, InlineForeignKeyField):
  334
+                exclude.append(f_name)
  335
+
325 336
         # Clean the model instance's fields.
326 337
         try:
327 338
             self.instance.clean_fields(exclude=exclude)
@@ -762,6 +773,7 @@ def get_unique_error_message(self, unique_check):
762 773
         unique_check = [field for field in unique_check if field != self.fk.name]
763 774
         return super(BaseInlineFormSet, self).get_unique_error_message(unique_check)
764 775
 
  776
+
765 777
 def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
766 778
     """
767 779
     Finds and returns the ForeignKey from model to parent if there is one
23  tests/regressiontests/admin_inlines/models.py
@@ -102,6 +102,29 @@ class Media:
102 102
 # only Inline media
103 103
 admin.site.register(Holder3, inlines=[InnerInline3])
104 104
 
  105
+# Models for #12749
  106
+
  107
+class Person(models.Model):
  108
+    firstname = models.CharField(max_length=15)
  109
+
  110
+class OutfitItem(models.Model):
  111
+    name = models.CharField(max_length=15)
  112
+
  113
+class Fashionista(models.Model):
  114
+    person = models.OneToOneField(Person, primary_key=True)
  115
+    weaknesses = models.ManyToManyField(OutfitItem, through='ShoppingWeakness', blank=True)
  116
+
  117
+class ShoppingWeakness(models.Model):
  118
+    fashionista = models.ForeignKey(Fashionista)
  119
+    item = models.ForeignKey(OutfitItem)
  120
+
  121
+class InlineWeakness(admin.TabularInline):
  122
+    model = ShoppingWeakness
  123
+    extra = 1
  124
+
  125
+admin.site.register(Fashionista, inlines=[InlineWeakness])
  126
+
  127
+
105 128
 __test__ = {'API_TESTS': """
106 129
 
107 130
 # Regression test for #9362
18  tests/regressiontests/admin_inlines/tests.py
@@ -3,7 +3,7 @@
3 3
 # local test models
4 4
 from models import Holder, Inner, InnerInline
5 5
 from models import Holder2, Inner2, Holder3, Inner3
6  
-
  6
+from models import Person, OutfitItem, Fashionista
7 7
 
8 8
 class TestInline(TestCase):
9 9
     fixtures = ['admin-views-users.xml']
@@ -48,6 +48,22 @@ def test_many_to_many_inlines(self):
48 48
         # The '+' is dropped from the autogenerated form prefix (Author_books+)
49 49
         self.assertContains(response, 'id="id_Author_books-TOTAL_FORMS"')
50 50
 
  51
+    def test_inline_primary(self):
  52
+        person = Person.objects.create(firstname='Imelda')
  53
+        item = OutfitItem.objects.create(name='Shoes')
  54
+        # Imelda likes shoes, but can't cary her own bags.
  55
+        data = {
  56
+            'shoppingweakness_set-TOTAL_FORMS': 1,
  57
+            'shoppingweakness_set-INITIAL_FORMS': 0,
  58
+            'shoppingweakness_set-MAX_NUM_FORMS': 0,
  59
+            '_save': u'Save',
  60
+            'person': person.id,
  61
+            'max_weight': 0,
  62
+            'shoppingweakness_set-0-item': item.id,
  63
+        }
  64
+        response = self.client.post('/test_admin/admin/admin_inlines/fashionista/add/', data)
  65
+        self.assertEqual(response.status_code, 302)
  66
+        self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
51 67
 
52 68
 class TestInlineMedia(TestCase):
53 69
     fixtures = ['admin-views-users.xml']

0 notes on commit dd07c23

Please sign in to comment.
Something went wrong with that request. Please try again.