Opened 6 years ago
Closed 6 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 , 6 years ago
| Type: | Uncategorized → Bug |
|---|
comment:2 by , 6 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 , 6 years ago
| Patch needs improvement: | set |
|---|
comment:4 by , 6 years ago
| Patch needs improvement: | unset |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
I agree we should fix this behavior when
remove_trailing_nulls=True.