#34711: form.has_changed() is always True for IntegerChoices Enum Model Field
------------------------+--------------------------------------
     Reporter:  GHPS    |                    Owner:  nobody
         Type:  Bug     |                   Status:  new
    Component:  Forms   |                  Version:  4.2
     Severity:  Normal  |               Resolution:
     Keywords:          |             Triage Stage:  Unreviewed
    Has patch:  0       |      Needs documentation:  0
  Needs tests:  0       |  Patch needs improvement:  0
Easy pickings:  0       |                    UI/UX:  0
------------------------+--------------------------------------
Description changed by GHPS:

Old description:

> Summary:
>
> While trying to find out why the forms in two different applications are
> marked for saving even if no field has been changed, I could pin the
> problem down
> to the integer enum fields used in both models and form.ChoiceField
> involved.
> In short form.has_changed() is triggered because of a double data
> conversion
> during the round-trip.
>
> The value of the integer enum field is converted to a string and
> rendered.
> The POST request comes back with this string which gets compared to the
> original
> enum integer which shows that they are different. During the -
> unnecessary - saving
> the string becomes an int again - which is why the original problem is
> hidden
> from the perspective of a user.
>
> Background:
>
> In Django 4.2 on Linux (Kubuntu 22.04) take the following enum and
> create a model field in model.py:
>
> {{{
> class eAssets(models.IntegerChoices):
>     dvd       =1, _('DVD')
>     bluray    =3, _('Blu-ray')
>     none      =0, _('-')
>
> eAsset=models.PositiveSmallIntegerField(choices=eAssets.choices,
> default=eAssets.none)
> }}}
>

> Create a choice form field in form.py:
>
> {{{
> eAsset=forms.ChoiceField(label=mdMovie._meta.get_field('eAsset').verbose_name,
> choices=[(dcEntry.value, dcEntry.label) for dcEntry in mdMovie.eAssets],
>                           initial=mdMovie.eAssets.none)
>
> After processing the POST request, form.has_changed() is always true in
> view.py:
>
> >fmForm=fmMovie(vRequest.POST, vRequest.FILES or None,
> instance=rcCurrentMovie)
> >fmForm.has_changed()
> True
> >fmForm.changed_data
> ['eAsset']
> }}}
>
> Links:
> - I've found an old ticket #22097 and it looks to me like this nine year
> old bug has shown its ugly face again.
> - On Stackoverflow someone reported the same problem.
> [https://stackoverflow.com/questions/68763230/django-forms-a-dynamic-
> integer-model-choice-field-always-fails-form-has-changed|A dynamic
> integer model choice field always fails form.has_changed()]

New description:

 Summary:

 While trying to find out why the forms in two different applications are
 marked for saving even if no field has been changed, I could pin the
 problem down
 to the integer enum fields used in both models and form.ChoiceField
 involved.
 In short, form.has_changed() is triggered because of a double data
 conversion
 during the round-trip.

 The value of the integer enum field is converted to a string and rendered.
 The POST request comes back with this string which gets compared to the
 original
 enum integer which shows that they are different. During the - unnecessary
 - saving
 the string becomes an int again - which is why the original problem is
 hidden
 from the perspective of a user.

 This bug seem to be a regression from bug #22097.

 Background:

 In Django 4.2 on Linux (Kubuntu 22.04) take the following enum and
 create a model field in model.py:

 {{{
 class eAssets(models.IntegerChoices):
     dvd       =1, _('DVD')
     bluray    =3, _('Blu-ray')
     none      =0, _('-')

 eAsset=models.PositiveSmallIntegerField(choices=eAssets.choices,
 default=eAssets.none)
 }}}


 Create a choice form field in form.py:

 {{{
 eAsset=forms.ChoiceField(label=mdMovie._meta.get_field('eAsset').verbose_name,
 choices=[(dcEntry.value, dcEntry.label) for dcEntry in mdMovie.eAssets],
                           initial=mdMovie.eAssets.none)
 }}}

 After processing the POST request, form.has_changed() is always true in
 view.py:

 {{{
 >fmForm=fmMovie(vRequest.POST, vRequest.FILES or None,
 instance=rcCurrentMovie)
 >fmForm.has_changed()
 True
 >fmForm.changed_data
 ['eAsset']
 }}}

 Links:
 - I've found an old ticket #22097 and it looks to me like this nine year
 old bug has shown its ugly face again.
 - On Stackoverflow someone reported the same problem.
 [https://stackoverflow.com/questions/68763230/django-forms-a-dynamic-
 integer-model-choice-field-always-fails-form-has-changed|A dynamic integer
 model choice field always fails form.has_changed()]

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34711#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018955bf4f13-7c474ca3-2750-4401-92eb-c5494afb0f57-000000%40eu-central-1.amazonses.com.

Reply via email to