﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
30907	SplitArrayField.has_changed() returns True for unchanged fields when using remove_trailing_nulls.	Pavel Dedik	Pavel Dedik	"This ticket addresses similar issue as in https://code.djangoproject.com/ticket/28950 only for the `SplitArrayField`

I have the following models and forms:


{{{
class Service(models.Model):
    name = pg_fields.CICharField(max_length=100)


class Environment(models.Model):
    service = models.ForeignKey(Service, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    urls = pg_fields.ArrayField(
        models.URLField(max_length=500), null=True, default=list
    )


class EnvironmentForm(forms.ModelForm):
    urls = SplitArrayField(
        forms.URLField(required=False),
        remove_trailing_nulls=True,
        required=False,
        size=2,
    )

    class Meta:
        model = models.Environment
        fields = [""name"", ""urls""]


ServiceEnvironmentsFormSet = forms.inlineformset_factory(
    models.Service,
    models.Environment,
    form=EnvironmentForm,
    extra=2,
    can_delete=True,
)

class ServiceForm(forms.ModelForm):
    class Meta:
        model = models.Service
        fields = [""name""]
}}}

Note the `ServiceEnvironmentsFormSet` which I'm rendering in a template including the `SplitArrayField` named `urls`. When I fill only the name of the `Service` in the rendered `ServiceForm` without entering any data to rendered `Environment` forms, the `ServiceEnvironmentsFormSet` validation fails. That's because in `EnvironmentForm`, the `name` is required, but that's not the problem - this should be ok when using `InlineFormSet` as each form in the FormSet is optional. So why does it fail? Because Django starts validating forms in `InlineFormSet` if the `form.has_changed()` method returns `True`. And in this case, it always returns `True` because `SplitArrayField.has_changed()` returns `True` in the following cases:


{{{
SplitArrayField.has_changed(None, ["""", """"])  # returns True even though it shouldn't as ["""", """"] means no data in the form has been entered
SplitArrayField.has_changed([], ["""", """"])  # returns True - should be False
SplitArrayField.has_changed([""a""], [""a"", """"])  # returns True - should be False
}}}

Note that I'm using `remove_trailing_nulls=True` in the `SplitArrayField`. So the above cases should all evaluate to `False` I believe.

I already opened PR for this here: https://github.com/django/django/pull/11970

BTW I'm not sure how `has_changed()` should be evaluated when passing both `remove_trailing_nulls=False` and `required=False` to the `base_field`, as in that case all required fields in the FormSet would have to be filled by the user since `has_changed()` would always return `True` even for empty input values."	Bug	closed	contrib.postgres	dev	Normal	fixed			Ready for checkin	1	0	0	0	0	0
