Commit 1a403aa7 authored by Simon Charette's avatar Simon Charette
Browse files

Fixed #25987 -- Made inline formset validation respect unique_together with an...

Fixed #25987 -- Made inline formset validation respect unique_together with an unsaved parent object.

Thanks Anton Kuzmichev for the report and Tim for the review.
parent 2c125bde
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -564,6 +564,9 @@ class BaseModelFormSet(BaseFormSet):
    """
    model = None

    # Set of fields that must be unique among forms of this set.
    unique_fields = set()

    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                 queryset=None, **kwargs):
        self.queryset = queryset
@@ -677,9 +680,11 @@ class BaseModelFormSet(BaseFormSet):
        for uclass, unique_check in all_unique_checks:
            seen_data = set()
            for form in valid_forms:
                # get data for each field of each of unique_check
                row_data = (form.cleaned_data[field]
                            for field in unique_check if field in form.cleaned_data)
                # Get the data for the set of fields that must be unique among the forms.
                row_data = (
                    field if field in self.unique_fields else form.cleaned_data[field]
                    for field in unique_check if field in form.cleaned_data
                )
                # Reduce Model instances to their primary key values
                row_data = tuple(d._get_pk_val() if hasattr(d, '_get_pk_val') else d
                                 for d in row_data)
@@ -878,6 +883,7 @@ class BaseInlineFormSet(BaseModelFormSet):
            qs = queryset.filter(**{self.fk.name: self.instance})
        else:
            qs = queryset.none()
        self.unique_fields = {self.fk.name}
        super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix,
                                                queryset=qs, **kwargs)

+3 −0
Original line number Diff line number Diff line
@@ -31,5 +31,8 @@ class Poem(models.Model):
    poet = models.ForeignKey(Poet, models.CASCADE)
    name = models.CharField(max_length=100)

    class Meta:
        unique_together = ('poet', 'name')

    def __str__(self):
        return self.name
+14 −0
Original line number Diff line number Diff line
@@ -162,3 +162,17 @@ class InlineFormsetFactoryTest(TestCase):
        PoemFormSet = inlineformset_factory(Poet, Poem, fields="__all__", extra=0)
        formset = PoemFormSet(None, instance=poet)
        self.assertEqual(len(formset.forms), 1)

    def test_unsaved_fk_validate_unique(self):
        poet = Poet(name='unsaved')
        PoemFormSet = inlineformset_factory(Poet, Poem, fields=['name'])
        data = {
            'poem_set-TOTAL_FORMS': '2',
            'poem_set-INITIAL_FORMS': '0',
            'poem_set-MAX_NUM_FORMS': '2',
            'poem_set-0-name': 'Poem',
            'poem_set-1-name': 'Poem',
        }
        formset = PoemFormSet(data, instance=poet)
        self.assertFalse(formset.is_valid())
        self.assertEqual(formset.non_form_errors(), ['Please correct the duplicate data for name.'])