lampShadesDrifter
lampShadesDrifter

Reputation: 4139

Django form field validator not raising error on field in template

Tried using this (Django: How to set DateField to only accept Today & Future dates) SO post to have form raise error in template when a date field is given value less than current date (which, based on another SO answer (https://stackoverflow.com/a/22513989/8236733), I thought was done via the form field validators (see https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-a-specific-field-attribute)). However, this does not seem to be working when inputting supposedly invalid values in the form template.

forms.py:

import datetime

from django import forms

from .models import Post


class MyForm(forms.Form):
    title = forms.CharField(max_length=100, required=True, help_text='Give a title',
                            widget=forms.TextInput(attrs={'size': '50rem'}))
    post = forms.CharField(max_length=280, required=True,
                           widget=forms.Textarea(attrs={'rows': 5}))
    expire_date = forms.DateField(  
        widget=forms.TextInput(attrs=
        {
            'class':'datepicker', # to use jquery datepicker
        }),
        required=True
    )
    expire_time = forms.TimeField(
        input_formats=['%H:%M %p'],
        widget=forms.TextInput(attrs=
        {
            'class':'timepicker', # to use jquery timepicker
        }),
        required=True)

    class Meta:
        model = Post
        fields = ('title', 'post', 'expire_date', 'expire_time',)

    def clean_date(self): # see https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-a-specific-field-attribute
        date = self.cleaned_data['expire_date']
        print(date)
        if date < datetime.date.today():
            raise forms.ValidationError("The date cannot be in the past!")
        return date

Relevant template snippet:

 <form method="post">
                {% csrf_token %}
                {% for field in listing_form %}
                <p>
                    {{ field.label_tag }}
                <div class="ui input">{{ field }}</div>
                {% if field.help_text %}
                <small class="ui inverted">{{ field.help_text }}</small>
                {% endif %}
                {% for error in field.errors %}
                <p style="color: red">{{ error }}</p>
                {% endfor %}
                </p>
                {% endfor %}
                <button class="ui inverted button" type="submit">submit</button>
                <div class="ui divider"></div>

                </small>
            </form>

Attempting to submit this form with some past date does not raise any error in the teplate and the form's is_valid() method raises no error in the backend view.

New to django, so is there something I am missing here? Do I need to somehow attach the validation method to the particular field in some way?

Upvotes: 0

Views: 718

Answers (1)

lampShadesDrifter
lampShadesDrifter

Reputation: 4139

Apparently it is important that the form method for cleaning / validating a particular form field follow a particular naming convention: clean_<field name>. This is shown implicitly in the docs (https://docs.djangoproject.com/en/2.0/ref/forms/validation/#cleaning-a-specific-field-attribute), but never stated outright. Changing the clean_... method in the form class in the original post to have the following code seems to have fixed the problem.

class MyForm(forms.Form):
    ....
    expire_date = forms.DateField(  
        widget=forms.TextInput(attrs=
        {
            'class':'datepicker', # to use jquery datepicker
        }),
        required=True
    )
    ....
    class Meta:
        model = Post
        fields = ('title', 'post', 'expire_date', 'expire_time',)

    def clean_expire_date(self): 
                date = self.cleaned_data['expire_date']
                print(date)
                if date < datetime.date.today():
                    raise forms.ValidationError("The date cannot be in the past!")
                return date

If anyone knows where in the docs this naming convention is more explicitly specified, please let me know.

Upvotes: 1

Related Questions