Skip to content
/ django Public

Fixed #29205 -- Corrected rendering of required attributes for MultiValueField subfields.#14034

Merged
carltongibson merged 1 commit intodjango:mainfrom
jacobtylerwalls:multiValueField-mixed-required
Aug 4, 2021
Merged

Fixed #29205 -- Corrected rendering of required attributes for MultiValueField subfields.#14034
carltongibson merged 1 commit intodjango:mainfrom
jacobtylerwalls:multiValueField-mixed-required

Conversation

@jacobtylerwalls
Copy link
Member

ticket-29205

Removed the HTML required attribute from subwidgets on a MultiValueField if the corresponding subfield is not required, and the MultiValueField has require_all_fields=False.

@jacobtylerwalls
Copy link
Member Author

Alternative to #12642

@smithdc1
Copy link
Member

Hi @jacobtylerwalls -- thanks for picking this up. This was one of the first tickets I looked at so almost certainly got myself tried up in knots!

At an initial glance this is much cleaner than whatever I was trying to do 🙈

@jacobtylerwalls
Copy link
Member Author

Thanks, David--haven't contributed in a few months, anything special I need to do for the whole suite to run?

@smithdc1
Copy link
Member

Let me try closing and reopening the pr... I think I have the right access to do this...

@smithdc1 smithdc1 closed this Feb 22, 2021
@smithdc1 smithdc1 reopened this Feb 22, 2021
@jacobtylerwalls
Copy link
Member Author

Looks like the last Jenkins build was 8 hours ago? Looks like it's not just this PR.

@smithdc1
Copy link
Member

Hi @felixxm -- seems to be an issue with Jenkins?

@jacobtylerwalls
Copy link
Member Author

Likely #14012 (comment)

@felixxm
Copy link
Member

felixxm commented Feb 23, 2021

Hi @felixxm -- seems to be an issue with Jenkins?

Yes, it should work now.

@jacobtylerwalls jacobtylerwalls force-pushed the multiValueField-mixed-required branch from 2a5f84e to d59f54d Compare February 23, 2021 12:54
Base automatically changed from master to main March 9, 2021 06:21
Copy link
Member

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jacobtylerwalls — Thanks for the work here. I know this ticket is difficult and has dragged on.

I think I'm missing the point of your approach here. It doesn't look to address the issue.

This change...

diff --git a/tests/forms_tests/field_tests/test_multivaluefield.py b/tests/forms_tests/field_tests/test_multivaluefield.py
index bcbdf0bc61..69d8cecb02 100644
--- a/tests/forms_tests/field_tests/test_multivaluefield.py
+++ b/tests/forms_tests/field_tests/test_multivaluefield.py
@@ -183,6 +183,6 @@ class MultiValueFieldTest(SimpleTestCase):
             'field1_2_0': '2007-04-25',
             'field1_2_1': '',  # not required
         })
-        form.is_valid()
+        self.assertTrue(form.is_valid())
         self.assertInHTML('<input type="text" name="f_0" required id="id_f_0">', form.as_p())
         self.assertInHTML('<input type="text" name="f_2_1" id="id_f_2_1">', form.as_p())

... fails...

======================================================================
FAIL: test_mixed_required_attributes (forms_tests.field_tests.test_multivaluefield.MultiValueFieldTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "...django/tests/forms_tests/field_tests/test_multivaluefield.py", line 186, in test_mixed_required_attributes
    self.assertTrue(form.is_valid())
AssertionError: False is not true

AFAICS the whole point of this ticket is that the required value on the sub-fields is not taken into account when require_all_fields is false.

The require_all_fields=True cases seems clear enough.

But when False (surely, no?) we need to defer to the individual fields — it's not enough to just adjust the rendered HTML. I think we need to look again. 🤔

@jacobtylerwalls jacobtylerwalls changed the title Fixed #29205 -- Removed required attribute from subwidgets on a MultiValueField where require_all_fields=False. Fixed #29205 -- Respected required attribute of subfields on MultiValueField subwidgets where require_all_fields=False. Aug 3, 2021
@jacobtylerwalls
Copy link
Member Author

jacobtylerwalls commented Aug 3, 2021

Hey Carlton, thanks for the review. I see that I've botched the test, because in trying to reuse existing fields, I didn't notice that ComplexFieldForm is "complex" because it uses nested MVFs. So without setting require_all_fields=False on the inner MVF (SplitDateTimeField) then I'm not really targeting the ticket's case! (In the current state of this PR, that inner level is in a confused state with both required=False and require_all_fields=True, which is nonsense. (EDIT: or, I guess, not exactly nonsense, but asking for no required attribute on the widget but enforcing errors on validation. Which is sort of what this test was showing.)

Given the test as written (which I should rewrite), I believe the failure of is_valid() is expected:

django/django/forms/fields.py

Lines 1163 to 1170 in c542d0a

def compress(self, data_list):
if data_list:
# Raise a validation error if time or date is empty
# (possible if SplitDateTimeField has required=False).
if data_list[0] in self.empty_values:
raise ValidationError(self.error_messages['invalid_date'], code='invalid_date')
if data_list[1] in self.empty_values:
raise ValidationError(self.error_messages['invalid_time'], code='invalid_time')

So -- I think the next step for me is to write a better test. I'm still not convinced we need any changes to validation, but I can hardly expect anyone to agree until I write an adequate test!

@jacobtylerwalls
Copy link
Member Author

OK, this test targets the ticket now. Shows the required attributes, shows form is valid, and fails on main. The reporter indicated this would have worked were it possible.

Let me know if you think I'm still missing something or desire additional tests.

@jacobtylerwalls
Copy link
Member Author

jacobtylerwalls commented Aug 3, 2021

Assuming we go this route, it's possible we want a small release note: if MVF has required=True, require_all_fields=False, and a subfield has required=False, the subfield won't be required. Could surprise someone who didn't know they had this configuration?

@carltongibson
Copy link
Member

Hey @jacobtylerwalls thanks for the quick update. Let me have another go in the morning 😜

@carltongibson carltongibson self-requested a review August 3, 2021 16:31
Copy link
Member

@smithdc1 smithdc1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi all,

I'll try and recall some of my thoughts on this, hope it is more help than hinderence. 🤞

I opened #14738 to show the current behaviour with the phonefield tests which I think cover all of the scenarios. Looking at the change here, Jacobs patch removes requied for the HTML for phone_3_3 (field required=True, require_all_fields=False, sub field required=False).

This fixes the 5th line on the truth table I posted a while back on the forum.

In the truth table I had suggested that the second row (field required=false, require_all_fields=False, sub field required=True) also needed adjusting. It's this scenario where I'm more uncertain what should happen. There are three aspects here:

a) HTML 5 required I had suggested that the html5 required labels should appear, I now think that's not the case as it's ok for all of the field to be empty. This PR meets this requirement. 👍

b) Field validation - all fields empty. Again, on the truth-table I had suggested that this scenario should raise an incomplete error if the entire field is not submitted. I now think this is incorrect. This addresses Carlton's observation here. This PR meets this requirement (i.e. doens't introduce a change) 👍

c) Field validation - some fields empty. So here, I'll refer to Carlton's previous comment as he can say it much more eloquently than me. "The MVF itself is optional. If submitted, and require_all_fields=False, we defer to the individual fields to determine if they can be omitted". I think the tests here which cover this scenario and don't look like they need adjusting. However, Calton -- you had pointed at the batch of tests above. Maybe this is where we have a different trail of thought? 🤔

I've not looked at the docs, do they need any work? To elaborate on Jacob's last point, some folk may find the above mentioned scenario surprising where required field is False but is True on a sub field and they can get an incomplete error?

Finally, one small backward(s) (I'm british so I can continue adding an "S", right?) comment inline below.

p.s. Carlton -- it amused me that this got picked up today 😉

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes that the number of fields and widgets is the same? I think that's ok, but it doesn't have to be the case today. Presumably this change would cause a crash if they are not of equal length?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for these notes and tests, David.

Good question. I cannot wait for Python 3.10 so I can start using zip(..., ..., strict=True)! I added a superfluous widget to my test case and nothing crashed; which makes sense, the iterator just quits early and that subwidget doesn't get a required attribute. I just don't know whether the fallback should be required or not required. My guess is not.

I see that I'm depending on the subfields and widgets corresponding in the same order, but I'm not aware of a need to support a case where they are not in the same order. I think you need to start subclassing your own widget at that point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Replying to #14034 (comment))

This seems to me like a question we can defer until a real-life case is reported.

Copy link
Member

@carltongibson carltongibson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, you've convinced me. 😅

Can you squash down @jacobtylerwalls? (Something like, Fixed #29205 -- Corrected required attr rendering for MultiValueField subfields.)

I think we should take the extra tests in #14738 as well.

Maybe this is where we have a different trail of thought? 🤔

No. I think I was pointing to the whole set of tests, rather than the specific case — I agree it does cover it.

I've not looked at the docs, do they need any work? To elaborate on Jacob's last point, some folk may find the above mentioned scenario surprising where required field is False but is True on a sub field and they can get an incomplete error?

I think they're OK. In particular I think the require_all_fields doc is pretty clear:

When set to False, the Field.required attribute can be set to False for individual fields to make them optional. If no value is supplied for a required field, an incomplete validation error will be raised.

https://docs.djangoproject.com/en/3.2/ref/forms/fields/#django.forms.MultiValueField.require_all_fields

Thanks both! 🎁

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Replying to #14034 (comment))

This seems to me like a question we can defer until a real-life case is reported.

@jacobtylerwalls jacobtylerwalls force-pushed the multiValueField-mixed-required branch from b161e7d to 85fdd01 Compare August 4, 2021 13:21
@jacobtylerwalls jacobtylerwalls changed the title Fixed #29205 -- Respected required attribute of subfields on MultiValueField subwidgets where require_all_fields=False. Fixed #29205 -- Corrected rendering of required attributes for MultiValueField subfields. Aug 4, 2021
@carltongibson carltongibson force-pushed the multiValueField-mixed-required branch from 85fdd01 to 2d0ae8d Compare August 4, 2021 15:37
@carltongibson carltongibson merged commit 2d0ae8d into django:main Aug 4, 2021
@jacobtylerwalls jacobtylerwalls deleted the multiValueField-mixed-required branch August 4, 2021 16:17
@smithdc1
Copy link
Member

smithdc1 commented Aug 5, 2021

Oh my, this one was quite the journey. Thank you both for the effort to think about and to review this. 🙏

Proves again that slow and steady wins the race. 🐢🐰🏁

I've had a other things on my plate the last couple days ... Next time I get some 'computer time' I'll polish the separate PR with the additional tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants