#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      |       Keywords:
           Triage Stage:  Unreviewed  |      Has patch:  0
    Needs documentation:  0           |    Needs tests:  0
Patch needs improvement:  0           |  Easy pickings:  0
                  UI/UX:  0           |
--------------------------------------+------------------------
 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()]

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34711>
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/0107018955ad1a4c-3fa767c7-5973-4998-85c5-39c1aae5ac45-000000%40eu-central-1.amazonses.com.

Reply via email to