#8898 closed Bug (fixed)
`required` validation bypassed when using `DateTimeField` with `SplitDateTimeWidget`.
| Reported by: | Tai Lee | Owned by: | nobody |
|---|---|---|---|
| Component: | Forms | Version: | dev |
| Severity: | Normal | Keywords: | DateTimeField SplitDateTimeWidget |
| Cc: | real.human@…, jarek.zgoda@…, doza@…, gertvangool@…, jgelens@… | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
DateTimeField.clean calls Field.clean for the required part of its validation, but Field.clean doesn't understand multiple values, and so DateTimeField.clean continues with the assumption that a value has been provided, which raises an invalid error incorrectly when the DateTimeField is *not* required and no values have been provided. This also means that an invalid error is raised instead of a required error when the DateTimeField *is* required and no values have been provided.
Attachments (2)
Change History (35)
by , 17 years ago
| Attachment: | 8898-DateTimeField-r8966.diff added |
|---|
comment:1 by , 17 years ago
comment:2 by , 17 years ago
| Summary: | `required` validation bypassed when using `SplitDateTimeWidget`. → `required` validation bypassed when using `DateTimeField` with `SplitDateTimeWidget`. |
|---|
comment:3 by , 17 years ago
| Triage Stage: | Unreviewed → Design decision needed |
|---|
After some further digging and discussion in #django-dev, I believe that the validation in DateTimeField.clean which is specific for SplitDateTimeWidget should be removed, and users should be guided to use SplitDateTimeField if they want to use SplitDateTimeWidget.
It seems that the intention is for MultiValueField and MultiValueWidget to be used together, and catching this edge case in DateTimeField to allow it to work with SplitDateTimeWidget actually makes it more difficult for users who might want to subclass DateTimeField and override clean to validate against their own MultiValueWidget, because the super class contains validation specifically for a two item tuple value from MultiValueWidget.
This special case validation doesn't actually work properly now anyway, as it bypasses the required validation.
I'm not sure about the history of DateTimeField or how and why this validation was added, so I'm bumping this to DDN.
comment:4 by , 17 years ago
| Cc: | added |
|---|
comment:5 by , 17 years ago
| Triage Stage: | Design decision needed → Accepted |
|---|
As per Karen's request, I'm moving this back to accepted, as the DDN was not intended to raise any red flags. The bug should be fixed, has a working patch with tests, and the previous suggestion to remove SplitDateTimeWidget validation from DateTimeField would be a backwards incompatible change that should have been raised in a separate ticket.
comment:6 by , 17 years ago
I don't believe the patch is correct as coded. DateTimeField is documented to return None for an empty value (http://docs.djangoproject.com/en/dev/ref/forms/fields/#datetimefield) and the patch has it returning a list in the case of empty input from a SplitDateTimeWidget. But it's not necessary to post another patch because that I could fix myself.
Before fixing this I think it would be good to understand why DateTimeField is even worried about getting input from a SplitDateTimeWidget. As noted above, it seems that is what SplitDateTimeField is for? The code was added in [6577] without reference to a ticket. Malcolm, do you recall why you added this? And do you have any recommendation as to whether it would be better to remove the half-working support entirely, make a fix along the lines of the patch, or ...? Strict backwards-compatibility would seem to require we can't remove it at this point....
comment:7 by , 17 years ago
| Patch needs improvement: | set |
|---|
follow-up: 10 comment:8 by , 17 years ago
If we can't remove it, and it seems we can't due to backwards compatibility (regardless of the reasons why it was added), can we get this fix committed? It's currently impossible to use an optional DateTimeField in the Django admin, with an exception being generated if no value is specified.
by , 17 years ago
| Attachment: | 8898-DateTimeField-r8983.diff added |
|---|
Update tests to match None return value.
comment:9 by , 17 years ago
| Patch needs improvement: | unset |
|---|
Just to make sure that the attached patch shouldn't be considered a red flag or incomplete, I've updated it to return None as per the documentation and updated the tests to match.
comment:10 by , 17 years ago
| Triage Stage: | Accepted → Design decision needed |
|---|
Replying to mrmachine:
It's currently impossible to use an optional DateTimeField in the Django admin, with an exception being generated if no value is specified.
That doesn't seem to be true; this works fine for me:
class Bug8898(models.Model):
timestamp = models.DateTimeField(blank=True, null=True)
I'm thinking there's not a bug here -- as Karen said, SplitDateTimeField is the right choice here -- but if there is can you please clarify how (if at all) this breaks forms and/or the admin?
comment:11 by , 17 years ago
| Cc: | added |
|---|
comment:12 by , 17 years ago
I was using a custom DateTimeField in my models which had a formfield() method that always used django.contrib.localflavor.generic.forms.DateTimeField as the form class so I wouldn't have to set input formats everywhere.
This was overriding the form class specified in BaseModelAdmin.formfield_for_dbfield for DateTimeField db fields and exposing the validation bug in forms.DateTimeField, which was to bypass the "required" validation when used with SplitDateTimeWidget.
In [9760] ModelAdmin.formfield_for_dbfield was re-factored and no longer treated my custom DateTimeField as a models.DateTimeField, because the new code checks if db_field.__class__ is in self.formfield_overrides instead of using isinstance().
To summarise:
- The bug in
forms.DateTimeFieldwhen used withSplitDateTimeWidgetstill exists, though this combination is not normally found in Django core. I suggest that we should still remove this vestigial code to avoid confusion and make subclassingforms.DateTimeFieldeasier. After all,MultiWidgetshould only be used withMultiValueField.
- A new bug (I'd call it a bug - it is a change in behaviour) exists where subclassed model fields are not recognised as their parent class in
BaseModelAdmin.formfield_for_dbfield(). I suppose the fix for this would be to loop overself.formfield_overridesand check withisinstance()in each iteration. When there's a match, updatekwargsand return.
comment:13 by , 17 years ago
The new bug I stumbled across already has a ticket with patch, #10059, but this vestigial code should still be removed :)
comment:14 by , 17 years ago
Also related: #9721. That one wants to mix together the SplitDateTimeWidget with a DateTimeField in order to allow for an optional time component. Perhaps that is why DateTimeField was given some support for getting input from a SplitDateTimeWidget in the first place? If so I think a better approach could be to add support for that kind of thing to the SplitDateTimeField/SplitDateTimeWidget combo rather than trying to mix a split widget with a non-split field.
comment:15 by , 16 years ago
| Cc: | added |
|---|
comment:16 by , 16 years ago
This bug has wider implications - if you have a form field with a MultiWidget, and you set it to required = False, then if you don't input anything in the widgets - it will tell you that you must input a value. The code which is flawed is this, inside clean() of a Field:
if value in EMPTY_VALUES:
return None
if you have 2 widgets then value == [, ] for an empty input, and the above doesn't work.
I will circumvent this in my code, but it'd be nice if it got corrected :)
comment:18 by , 16 years ago
Another idea could be to attach EMPTY_VALUES to the Field and have the Widget edit it.
I bypassed this bug using forms.SplitDateTimeField.
comment:20 by , 15 years ago
| Triage Stage: | Design decision needed → Accepted |
|---|
I agree with Karen that DateTimeField should not be used with SplitDateTimeWidget, and that adding ad-hoc multi-widget support to formfield clean() methods is a bad idea. That code in DateTimeField.clean() can't be removed immediately due to backwards-compat, but I would consider a patch with a PendingDeprecationWarning that refers people to SplitDateTimeField and allows us to remove that code in a couple releases. This should come with appropriate documentation and a note in the deprecation docs as well.
comment:21 by , 15 years ago
| Cc: | added |
|---|
comment:22 by , 15 years ago
| Patch needs improvement: | set |
|---|
Marking as patch needs improvement on the basis of Carl's comments.
comment:26 by , 12 years ago
| Patch needs improvement: | unset |
|---|
comment:27 by , 12 years ago
Reading ticket #9721, it appears that DateTimeField with SplitDateTimeWidget may be used when only the time part of the field is optional, which would not be possible with SplitDateTimeField. To be investigated...
comment:28 by , 12 years ago
It may be that #15511 filled the above use case (setting require_all_fields to False, then SplitDateTimeField.fields[1].required to False in a SplitDateTimeField subclass).
@mrmachine, can you confirm?
comment:29 by , 12 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Needs a line in the release notes, otherwise LGTM.
comment:30 by , 12 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
The attachment above includes tests for both cases (required and not required) which fail before the patch is applied, and pass after it is applied.