Loading django/forms/models.py +9 −1 Original line number Diff line number Diff line Loading @@ -800,7 +800,10 @@ class BaseModelFormSet(BaseFormSet): or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk))) if pk_is_not_editable(pk) or pk.name not in form.fields: if form.is_bound: pk_value = form.instance.pk # If we're adding the related instance, ignore its primary key # as it could be an auto-generated default which isn't actually # in the database. pk_value = None if form.instance._state.adding else form.instance.pk else: try: if index is not None: Loading Loading @@ -928,6 +931,11 @@ class BaseInlineFormSet(BaseModelFormSet): if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name: kwargs['to_field'] = self.fk.rel.field_name # If we're adding a new object, ignore a parent's auto-generated pk # as it will be regenerated on the save request. if self.instance._state.adding and form._meta.model._meta.pk.has_default(): self.instance.pk = None form.fields[name] = InlineForeignKeyField(self.instance, **kwargs) # Add the generated field to form._meta.fields if it's defined to make Loading tests/model_formsets/models.py +13 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import datetime import uuid from django.db import models from django.utils import six Loading Loading @@ -241,3 +242,15 @@ class Post(models.Model): def __str__(self): return self.name # Models for testing UUID primary keys class UUIDPKParent(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) class UUIDPKChild(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) parent = models.ForeignKey(UUIDPKParent) tests/model_formsets/test_uuid.py 0 → 100644 +32 −0 Original line number Diff line number Diff line from django.forms.models import inlineformset_factory from django.test import TestCase from .models import UUIDPKChild, UUIDPKParent class InlineFormsetTests(TestCase): def test_inlineformset_factory_nulls_default_pks(self): """ #24377 - If we're adding a new object, a parent's auto-generated pk from the model field default should be ignored as it's regenerated on the save request. """ FormSet = inlineformset_factory(UUIDPKParent, UUIDPKChild, fields='__all__') formset = FormSet() self.assertIsNone(formset.forms[0].fields['parent'].initial) def test_inlineformset_factory_ignores_default_pks_on_submit(self): """ #24377 - Inlines with a model field default should ignore that default value to avoid triggering validation on empty forms. """ FormSet = inlineformset_factory(UUIDPKParent, UUIDPKChild, fields='__all__') formset = FormSet({ 'uuidpkchild_set-TOTAL_FORMS': 3, 'uuidpkchild_set-INITIAL_FORMS': 0, 'uuidpkchild_set-MAX_NUM_FORMS': '', 'uuidpkchild_set-0-name': 'Foo', 'uuidpkchild_set-1-name': '', 'uuidpkchild_set-2-name': '', }) self.assertTrue(formset.is_valid()) Loading
django/forms/models.py +9 −1 Original line number Diff line number Diff line Loading @@ -800,7 +800,10 @@ class BaseModelFormSet(BaseFormSet): or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk))) if pk_is_not_editable(pk) or pk.name not in form.fields: if form.is_bound: pk_value = form.instance.pk # If we're adding the related instance, ignore its primary key # as it could be an auto-generated default which isn't actually # in the database. pk_value = None if form.instance._state.adding else form.instance.pk else: try: if index is not None: Loading Loading @@ -928,6 +931,11 @@ class BaseInlineFormSet(BaseModelFormSet): if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name: kwargs['to_field'] = self.fk.rel.field_name # If we're adding a new object, ignore a parent's auto-generated pk # as it will be regenerated on the save request. if self.instance._state.adding and form._meta.model._meta.pk.has_default(): self.instance.pk = None form.fields[name] = InlineForeignKeyField(self.instance, **kwargs) # Add the generated field to form._meta.fields if it's defined to make Loading
tests/model_formsets/models.py +13 −0 Original line number Diff line number Diff line from __future__ import unicode_literals import datetime import uuid from django.db import models from django.utils import six Loading Loading @@ -241,3 +242,15 @@ class Post(models.Model): def __str__(self): return self.name # Models for testing UUID primary keys class UUIDPKParent(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) class UUIDPKChild(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=255) parent = models.ForeignKey(UUIDPKParent)
tests/model_formsets/test_uuid.py 0 → 100644 +32 −0 Original line number Diff line number Diff line from django.forms.models import inlineformset_factory from django.test import TestCase from .models import UUIDPKChild, UUIDPKParent class InlineFormsetTests(TestCase): def test_inlineformset_factory_nulls_default_pks(self): """ #24377 - If we're adding a new object, a parent's auto-generated pk from the model field default should be ignored as it's regenerated on the save request. """ FormSet = inlineformset_factory(UUIDPKParent, UUIDPKChild, fields='__all__') formset = FormSet() self.assertIsNone(formset.forms[0].fields['parent'].initial) def test_inlineformset_factory_ignores_default_pks_on_submit(self): """ #24377 - Inlines with a model field default should ignore that default value to avoid triggering validation on empty forms. """ FormSet = inlineformset_factory(UUIDPKParent, UUIDPKChild, fields='__all__') formset = FormSet({ 'uuidpkchild_set-TOTAL_FORMS': 3, 'uuidpkchild_set-INITIAL_FORMS': 0, 'uuidpkchild_set-MAX_NUM_FORMS': '', 'uuidpkchild_set-0-name': 'Foo', 'uuidpkchild_set-1-name': '', 'uuidpkchild_set-2-name': '', }) self.assertTrue(formset.is_valid())