Ticket #12749: t12749.diff

File t12749.diff, 4.9 KB (added by russellm, 5 years ago)

Updated, fully working patch.

  • django/db/models/fields/related.py

    diff -r f681ed7ea9ad django/db/models/fields/related.py
    a b  
    824824    def validate(self, value, model_instance):
    825825        if self.rel.parent_link:
    826826            return
    827         # Don't validate the field if a value wasn't supplied. This is
    828         # generally the case when saving new inlines in the admin.
    829         # See #12507.
     827        super(ForeignKey, self).validate(value, model_instance)
    830828        if value is None:
    831829            return
    832         super(ForeignKey, self).validate(value, model_instance)
    833         if not value:
    834             return
    835830
    836831        qs = self.rel.to._default_manager.filter(**{self.rel.field_name:value})
    837832        qs = qs.complex_filter(self.rel.limit_choices_to)
  • django/forms/models.py

    diff -r f681ed7ea9ad django/forms/models.py
    a b  
    316316        return self.cleaned_data
    317317
    318318    def _post_clean(self):
    319         exclude = self._get_validation_exclusions()
    320319        opts = self._meta
    321 
    322320        # Update the model instance with self.cleaned_data.
    323321        self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
    324322
     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
    325336        # Clean the model instance's fields.
    326337        try:
    327338            self.instance.clean_fields(exclude=exclude)
     
    762773        unique_check = [field for field in unique_check if field != self.fk.name]
    763774        return super(BaseInlineFormSet, self).get_unique_error_message(unique_check)
    764775
     776
    765777def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
    766778    """
    767779    Finds and returns the ForeignKey from model to parent if there is one
  • tests/regressiontests/admin_inlines/models.py

    diff -r f681ed7ea9ad tests/regressiontests/admin_inlines/models.py
    a b  
    8888# only Inline media
    8989admin.site.register(Holder3, inlines=[InnerInline3])
    9090
     91# Models for #12749
     92
     93class Person(models.Model):
     94    firstname = models.CharField(max_length=15)
     95
     96class OutfitItem(models.Model):
     97    name = models.CharField(max_length=15)
     98
     99class Fashionista(models.Model):
     100    person = models.OneToOneField(Person, primary_key=True)
     101    weaknesses = models.ManyToManyField(OutfitItem, through='ShoppingWeakness', blank=True)
     102
     103class ShoppingWeakness(models.Model):
     104    fashionista = models.ForeignKey(Fashionista)
     105    item = models.ForeignKey(OutfitItem)
     106
     107class InlineWeakness(admin.TabularInline):
     108    model = ShoppingWeakness
     109    extra = 1
     110
     111admin.site.register(Fashionista, inlines=[InlineWeakness])
     112
     113
    91114__test__ = {'API_TESTS': """
    92115
    93116# Regression test for #9362
  • tests/regressiontests/admin_inlines/tests.py

    diff -r f681ed7ea9ad tests/regressiontests/admin_inlines/tests.py
    a b  
    33# local test models
    44from models import Holder, Inner, InnerInline
    55from models import Holder2, Inner2, Holder3, Inner3
    6 
     6from models import Person, OutfitItem, Fashionista
    77
    88class TestInline(TestCase):
    99    fixtures = ['admin-views-users.xml']
     
    3838                                   % holder.id)
    3939        self.assertContains(response, '<label>Inner readonly label:</label>')
    4040
     41    def test_inline_primary(self):
     42        person = Person.objects.create(firstname='Imelda')
     43        item = OutfitItem.objects.create(name='Shoes')
     44        # Imelda likes shoes, but can't cary her own bags.
     45        data = {
     46            'shoppingweakness_set-TOTAL_FORMS': 1,
     47            'shoppingweakness_set-INITIAL_FORMS': 0,
     48            'shoppingweakness_set-MAX_NUM_FORMS': 0,
     49            '_save': u'Save',
     50            'person': person.id,
     51            'max_weight': 0,
     52            'shoppingweakness_set-0-item': item.id,
     53        }
     54        response = self.client.post('/test_admin/admin/admin_inlines/fashionista/add/', data)
     55        self.assertEqual(response.status_code, 302)
     56        self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1)
    4157
    4258class TestInlineMedia(TestCase):
    4359    fixtures = ['admin-views-users.xml']
Back to Top