form works, but form.is_valid() returns false

I am working on a form that takes two dates and then fetches all the database rows whose timestamp value is between the begin and end dates.

class DateForm(forms.Form):
    """Form for the date fields in which the user can see which month is
    currently selected, and also change it.
    """
    begin_date = forms.DateField(
        label='Begin Date',
        widget=forms.SelectDateWidget(years=range(1990, 2040))
    )

    end_date = forms.DateField(
        label='End Date',
        widget=forms.SelectDateWidget(years=range(1990, 2040))
    )

    def clean(self):
        cleaned_data = super().clean()
        begin_date = cleaned_data.get('begin_date')
        end_date = cleaned_data.get('end_date')

        # Check if begin_date is less than end_date
        if begin_date and end_date and begin_date >= end_date:
            cleaned_data['begin_date'], cleaned_data['end_date'] = end_date, begin_date

        return cleaned_data

In my def show(request, process_name, begin_date=False, end_date=False) function I call the form like this:

initial_data = {'begin_date': begin_date,
                        'end_date': end_date}
date_form = DateForm(initial=initial_data)

where begin_date and end_date are valid string objects.

But when I call date_form.is_valid(), it returns false:

I tried printing all errors using date_form.errors.as_data() and date_form.errors, but I only got an empty dictionary.

I also tried converting begin_date and end_date to datetime.datetime, but it does not change anything.

When I use the form to get the rows within the specific dates, it does work. What’s going on here?

Please post the view where you are doing this work.

Hi, here is the show function:

def show(request, p_name, begin_date=False, end_date=False):
    pc = get_all_models()[p_name]
    p_name = "test"
    namespace = pc._meta.app_label

    initial_data = {'begin_date': begin_date,
                    'end_date': end_date}
    date_form = DateForm(initial=initial_data)
    
    template = loader.get_template("samples/xxx_" + process_name + ".html")
    template_context = RequestContext(request, pc.get_xxx_context_range(begin_date, end_date))
    template_context["request"] = request
    html_body = template.render(template_context.flatten())
    try:
        if date_form.is_valid():
            export_url = django.urls.reverse(
                "{}:export_xxx_{}".format(namespace, p_name),
                kwargs={'begin_date': datetime.strptime(begin_date, "%Y-%m-%d"),
                        'end_date': datetime.strptime(end_date, "%Y-%m-%d")}) + "?next=" + quote_plus(request.path)
    except django.urls.NoReverseMatch:
        export_url = None
    return render(request, "samples/xxx.html",
                  {
                   "html_body": html_body, 
                   "export_url": export_url})

You’re creating an unbound form with initial values, you’re not “binding” the data to the forms as if it were being submitted. The is_valid function is always going to be false for unbound forms.

Read the docs (and the examples) at Bound and unbound forms.