Opened 6 years ago
Closed 6 years ago
#30596 closed Bug (fixed)
SplitArrayField.has_changed() is always True for numeric fields.
| Reported by: | Evgeniy Krysanov | Owned by: | Chason Chaffin |
|---|---|---|---|
| Component: | contrib.postgres | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Code example:
# models.py
class Signal(models.Model):
order_price = ArrayField(models.FloatField(), default=list)
# admin.py
class SignalForm(forms.ModelForm):
order_price = SplitArrayField(base_field=forms.FloatField(), size=3, remove_trailing_nulls=True, required=False)
@admin.register(Signal)
class SignalAdmin(admin.ModelAdmin):
form = SignalForm
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
print(form.has_changed()) # Always True even if no values was changed
Attachments (1)
Change History (7)
follow-up: 2 comment:1 by , 6 years ago
comment:2 by , 6 years ago
Replying to felixxm:
I was not able to reproduce this issue in basic tests. Maybe it is related
remove_trailing_nulls=True, do you have them in a database? e.g.[1.33, 5.33. 8.78, None]Can you check initial data?
I checked a lot of cases until I isolated the problem - https://github.com/django/django/blob/master/django/forms/forms.py#L451
initial_value is the original object's value, for example [3.5, 1.0, 2.2]. data_value is converted from form data to ['3.5', '1.0', '2.2'], but not converted to FloatField values. If the initial_value is [] then the data_value is ['', '', '']. Thats why has_changed always returns True.
I fixed this bug in my project with the following code:
class BetterSplitArrayField(SplitArrayField):
def to_python(self, value):
return self.clean(value)
When calling field.has_changed(initial_value, data_value)there is a call to data = self.to_python(data) https://github.com/django/django/blob/master/django/forms/fields.py#L181 but SplitArrayField just returns the original value from this method. My code fix this.
But it would be better to see the fix in Django source. I can write a PR with unitests if you wish.
comment:3 by , 6 years ago
| Component: | Forms → contrib.postgres |
|---|---|
| Summary: | Form method `has_changed` always returns True if form has the SplitArrayField field → SplitArrayField.has_changed() is always True for numeric fields. |
| Triage Stage: | Unreviewed → Accepted |
| Version: | 2.2 → master |
Thanks for details. I was able to reproduce this issue.
comment:4 by , 6 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
I was not able to reproduce this issue in basic tests. Maybe it is related
remove_trailing_nulls=True, do you have them in a database? e.g.[1.33, 5.33. 8.78, None]Can you check initial data?