Opened 5 years ago
Closed 5 years ago
#30907 closed Bug (fixed)
SplitArrayField.has_changed() returns True for unchanged fields when using remove_trailing_nulls.
Reported by: | Pavel Dedik | Owned by: | Pavel Dedik |
---|---|---|---|
Component: | contrib.postgres | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Ready for checkin | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
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.
Change History (7)
comment:1 by , 5 years ago
Type: | Uncategorized → Bug |
---|
comment:2 by , 5 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
Summary: | SplitArrayField.has_changed() returns True for unchanged fields → SplitArrayField.has_changed() returns True for unchanged fields when using remove_trailing_nulls. |
Triage Stage: | Unreviewed → Accepted |
Version: | 2.2 → master |
comment:3 by , 5 years ago
Patch needs improvement: | set |
---|
comment:4 by , 5 years ago
Patch needs improvement: | unset |
---|---|
Triage Stage: | Accepted → Ready for checkin |
I agree we should fix this behavior when
remove_trailing_nulls=True
.