From 06a11ef6ecf324db0a1530b8cca727883698f442 Mon Sep 17 00:00:00 2001 From: Demur Nodia Date: Sun, 27 May 2018 13:06:37 +0300 Subject: [PATCH] Fixed #26819 -- Fixed BaseModelFormSet.validate_unique() "unhashable type: list" crash. --- django/forms/models.py | 8 ++++++-- tests/model_formsets/tests.py | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/django/forms/models.py b/django/forms/models.py index 7f5e2544dd..aa35ef5f92 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -696,8 +696,12 @@ class BaseModelFormSet(BaseFormSet): 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) + row_data = tuple( + d._get_pk_val() if hasattr(d, '_get_pk_val') + # Prevent "unhashable type: list" errors later on. + else tuple(d) if isinstance(d, list) + else d for d in row_data + ) if row_data and None not in row_data: # if we've already seen it then we have a uniqueness failure if row_data in seen_data: diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py index 4d00a589ce..d823a78ae8 100644 --- a/tests/model_formsets/tests.py +++ b/tests/model_formsets/tests.py @@ -1459,6 +1459,33 @@ class ModelFormsetTest(TestCase): self.assertEqual(player1.team, team) self.assertEqual(player1.name, 'Bobby') + def test_inlineformset_with_arrayfield(self): + class SimpleArrayField(forms.CharField): + """A proxy for django.contrib.postgres.forms.SimpleArrayField.""" + def to_python(self, value): + value = super().to_python(value) + return value.split(',') if value else [] + + class BookForm(forms.ModelForm): + title = SimpleArrayField() + + class Meta: + model = Book + fields = ('title',) + + BookFormSet = inlineformset_factory(Author, Book, form=BookForm) + data = { + 'book_set-TOTAL_FORMS': '3', + 'book_set-INITIAL_FORMS': '0', + 'book_set-MAX_NUM_FORMS': '', + 'book_set-0-title': 'test1,test2', + 'book_set-1-title': 'test1,test2', + 'book_set-2-title': 'test3,test4', + } + author = Author.objects.create(name='test') + formset = BookFormSet(data, instance=author) + self.assertEqual(formset.errors, [{}, {'__all__': ['Please correct the duplicate values below.']}, {}]) + def test_model_formset_with_custom_pk(self): # a formset for a Model that has a custom primary key that still needs to be # added to the formset automatically