Commit 42968014 authored by Jason Hoos's avatar Jason Hoos Committed by Tim Graham
Browse files

[1.8.x] Fixed #24958 -- Fixed inline forms using UUID-PK parents with auto-PK children.

Backport of a50b66da from master
parent a97e50c5
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -922,10 +922,15 @@ 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
        # If we're adding a new object, ignore a parent's auto-generated key
        # 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
        if self.instance._state.adding:
            if kwargs.get('to_field') is not None:
                to_field = self.instance._meta.get_field(kwargs['to_field'])
            else:
                to_field = self.instance._meta.pk
            if to_field.has_default():
                setattr(self.instance, to_field.attname, None)

        form.fields[name] = InlineForeignKeyField(self.instance, **kwargs)

+4 −0
Original line number Diff line number Diff line
@@ -85,3 +85,7 @@ Bugfixes

* Reallowed non-ASCII values for ``ForeignKey.related_name`` on Python 3 by
  fixing the false positive system check (:ticket:`25016`).

* Fixed inline forms that use a parent object that has a ``UUIDField`` primary
  key and a child object that has an ``AutoField`` primary key
  (:ticket:`24958`).
+30 −0
Original line number Diff line number Diff line
@@ -254,3 +254,33 @@ 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)


class ChildWithEditablePK(models.Model):
    name = models.CharField(max_length=255, primary_key=True)
    parent = models.ForeignKey(UUIDPKParent)


class AutoPKChildOfUUIDPKParent(models.Model):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey(UUIDPKParent)


class AutoPKParent(models.Model):
    name = models.CharField(max_length=255)


class UUIDPKChildOfAutoPKParent(models.Model):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    parent = models.ForeignKey(AutoPKParent)


class ParentWithUUIDAlternateKey(models.Model):
    uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=50)


class ChildRelatedViaAK(models.Model):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey(to=ParentWithUUIDAlternateKey, to_field='uuid')
+47 −1
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
from .models import (
    AutoPKChildOfUUIDPKParent, AutoPKParent, ChildRelatedViaAK,
    ChildWithEditablePK, ParentWithUUIDAlternateKey, UUIDPKChild,
    UUIDPKChildOfAutoPKParent, UUIDPKParent,
)


class InlineFormsetTests(TestCase):
@@ -10,6 +14,8 @@ class InlineFormsetTests(TestCase):
        #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.

        Tests the case where both the parent and child have a UUID primary key.
        """
        FormSet = inlineformset_factory(UUIDPKParent, UUIDPKChild, fields='__all__')
        formset = FormSet()
@@ -30,3 +36,43 @@ class InlineFormsetTests(TestCase):
            'uuidpkchild_set-2-name': '',
        })
        self.assertTrue(formset.is_valid())

    def test_inlineformset_factory_nulls_default_pks_uuid_parent_auto_child(self):
        """
        #24958 - Variant of test_inlineformset_factory_nulls_default_pks for
        the case of a parent object with a UUID primary key and a child object
        with an AutoField primary key.
        """
        FormSet = inlineformset_factory(UUIDPKParent, AutoPKChildOfUUIDPKParent, fields='__all__')
        formset = FormSet()
        self.assertIsNone(formset.forms[0].fields['parent'].initial)

    def test_inlineformset_factory_nulls_default_pks_auto_parent_uuid_child(self):
        """
        #24958 - Variant of test_inlineformset_factory_nulls_default_pks for
        the case of a parent object with an AutoField primary key and a child
        object with a UUID primary key.
        """
        FormSet = inlineformset_factory(AutoPKParent, UUIDPKChildOfAutoPKParent, fields='__all__')
        formset = FormSet()
        self.assertIsNone(formset.forms[0].fields['parent'].initial)

    def test_inlineformset_factory_nulls_default_pks_child_editable_pk(self):
        """
        #24958 - Variant of test_inlineformset_factory_nulls_default_pks for
        the case of a parent object with a UUID primary key and a child
        object with an editable natural key for a primary key.
        """
        FormSet = inlineformset_factory(UUIDPKParent, ChildWithEditablePK, fields='__all__')
        formset = FormSet()
        self.assertIsNone(formset.forms[0].fields['parent'].initial)

    def test_inlineformset_factory_nulls_default_pks_alternate_key_relation(self):
        """
        #24958 - Variant of test_inlineformset_factory_nulls_default_pks for
        the case of a parent object with a UUID alternate key and a child
        object that relates to that alternate key.
        """
        FormSet = inlineformset_factory(ParentWithUUIDAlternateKey, ChildRelatedViaAK, fields='__all__')
        formset = FormSet()
        self.assertIsNone(formset.forms[0].fields['parent'].initial)