Form.has_changed() == False and Form.changed_data empty

467 views
Skip to first unread message

Lars Liedtke

unread,
Apr 11, 2021, 10:50:19 AM4/11/21
to django-users
Hello,

I have got two checkboxes in a Form on Django 3.1, with which everything
works fine, but unchecking them.

I use a class derived from UpdateView and in its post() method I check
for if my form has changed. This works fine for an initial empty form
and checking form.has_changed(); after then handling the change and
calling get() with the objects id in the Browser. I get the Form back
with checked checkboxes. The values in the database are fine as well.

So now I want to test with unchecking those checkboxes and it does not
work. Form.has_changed() == False and Form.changed_data is empty. While
the correct values are in Form.cleaned_data(). But my code does not
detect these values because I check for Form.has_changed().

Am I understanding something wrong here or do I have to check if there
is a difference from the values I get in Form.cleaned_data to what my
current state in the database is myself?

I am happy to show the code. But I thought I'd ask about it in general
before posting lots of code.

---
punkt.de GmbH
Lars Liedtke
.infrastructure

Kaiserallee 13a
76133 Karlsruhe

Tel. +49 721 9109 500
https://infrastructure.punkt.de
in...@punkt.de

AG Mannheim 108285
Geschäftsführer: Jürgen Egeling, Daniel Lienert, Fabian Stein

Gabriel Araya Garcia

unread,
Apr 11, 2021, 11:14:20 AM4/11/21
to django...@googlegroups.com
I have checkboxes in my css grid and there is name, type=chekbox", etc. In may view django I have captured the value of the check template with             valor_xx = request.POST.get(str(xx))   # valor del check directamente desde template
in POST method.
But, all of this in my view based in function.
Last night finished with this and I'd checked this running perfectly.
 You have take in mind that in template you must ask if the value check field is chequed or not with {% if.. %}..{%else%}{%endif%}. This is sent from context.
If you need some help,
Regards  
 
Gabriel Araya Garcia
GMI - Desarrollo de Sistemas Informáticos
Santiago de Chile



--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/13e0719e-8d06-e37c-b07e-1c6deb1f84e6%40punkt.de.

Lars Liedtke

unread,
Apr 12, 2021, 2:45:56 AM4/12/21
to django...@googlegroups.com, Gabriel Araya Garcia

Hello Gabriel,

thank you for your reply, I use the widgets own rendering in my template.

{{ form.customer }}

where "form" is the Form class and customer the checkbox-widget passed via the context.

The Problem is not a rendering Problem (I think) because the checkbox works as intended. Only the information that the checkbox has been changed from checked to unchecked with a new post request, is not recognized inside the post() method of my view. The values in Form.cleaned_data represent the correct values (customer is False, where it was True in the request before). But due to the fact that I am checking for Form.is_changed() my code does not detect the change. Also Form.changed_data does not contain "customer". THis is my code in post(), I've added some comments:

    def post(self, request, *args, **kwargs):
        company: models.Company = get_object_or_404(models.Company, pk=kwargs['pk'])
        self.initialize_forms(request, company) # initializes the Form and its Formsets
        if not_valid := self._check_form_validity(request, *args, **kwargs):
            return not_valid

        if self.company_form.has_changed(): # This is False!
            if 'agency' in self.company_form.changed_data:
                self.__update_company_type(company, models.Agency)
            if 'customer' in self.company_form.changed_data: # company_form does not contain "customer"
                self.__update_company_type(company, models.Customer)
            company = self.company_form.save()
        if self.address_formset.has_changed():
            self.address_formset.save()
        if self.ssh_key_formset.has_changed():
            self.ssh_key_formset.save()
        if self.email_formset.has_changed():
            self.email_formset.save()

The raw Post-Request is correct as well, I checked in my browser and in my tests. This is how I try to test the unchecking:

class UpdateCompanyViewsTests(TestCase):
    POST_REQUEST_DATA = dict({'name': "Apu's Kwik'E'Mart",
                              'addresses-TOTAL_FORMS': '1',
                              'addresses-INITIAL_FORMS': '0',
                              'addresses-MIN_NUM_FORMS': '0',
                              'addresses-MAX_NUM_FORMS': '1000',
                              'addresses-0-street': '',
                              'addresses-0-number': '',
                              'addresses-0-postcode': '',
                              'addresses-0-place': '',
                              'addresses-0-country_code': '',
                              'ssh_keys-TOTAL_FORMS': '1',
                              'ssh_keys-INITIAL_FORMS': '0',
                              'ssh_keys-MIN_NUM_FORMS': '0',
                              'ssh_keys-MAX_NUM_FORMS': '1000',
                              'ssh_keys-0-ssh_key': '',
                              'email_addresses-TOTAL_FORMS': '1',
                              'email_addresses-INITIAL_FORMS': '0',
                              'email_addresses-MIN_NUM_FORMS': '0',
                              'email_addresses-MAX_NUM_FORMS': '1000',
                              'email_addresses-0-email_address': ''
                              })

[...]

def test_post_company_edit_type_remove_customer(self):
        company = Company.objects.create(id='1', name="Apu's Kwik'E'Mart")
        get_response = self.client.get(f'/company/1/')
        post_set_customer_data = {**self.POST_REQUEST_DATA,
                                  'csrfmiddlewaretoken': get_response.cookies['csrftoken'].value,
                                  'agency': '',
                                  'customer': 'on',
                                  }
        post_set_customer_response = self.client.post(f'/company/1/', data=post_set_customer_data, follow=True)
        self.assertEqual(post_set_customer_response.status_code, 200)
        post_remove_customer_data = {**self.POST_REQUEST_DATA,
                                     'csrfmiddlewaretoken': post_set_customer_response.cookies['csrftoken'].value,
                                     'agency': '',
                                     'customer': '',
                                     }
        post_remove_customer_response = self.client.post(f'/company/1/', data=post_remove_customer_data, follow=True)
        self.assertEqual(post_remove_customer_response.status_code, 200)
        self.assertFalse(hasattr(company, 'customer'))

and this test fails because company still has got the customer attribute.

Am 12.04.21 um 16:12 schrieb Gabriel Araya Garcia:

Reply all
Reply to author
Forward
0 new messages