Django form – use different pre defined date ranges for different choices

Issue

I have a Django form where the user can select a variable in a choice field, start date and end date in a select date widget. For different variables, the possible start and end dates varies. The form works, but only with one pre-defined date range for all variables. How can I change the possible start and end dates according to the variable?

from django import forms
from datetime import datetime 

Parameter_CHOICES = [
    ('', 'Wähle ein Umweltvariable'),
    ('niederschlag', 'Niederschlag [L/m²]'),
    ('bodentemperatur_5cm', 'Bodentemperatur in 5cm Tiefe [°C]')
]

class DataForm(forms.Form):
    parameter = forms.ChoiceField(
        widget=forms.Select,
        choices=Parameter_CHOICES)
    start_date = forms.DateField(label='Beginn:', widget=forms.SelectDateWidget(years=list(range(2007,2023))))
    end_date = forms.DateField(label='Ende:', initial=datetime.now, widget=forms.SelectDateWidget(years=list(range(2007,2023))))

What i need is to set the
years=list(range(2007,2023))
for niederschlag
and for bodentemperatur_5cm to
years=list(range(1991,2023))

Is it possible to do this in the forms.py or do I have to make this in javascript/html?

Update
I try to solve it with jQuery, but I stuck.
I try to change the Years Range choicec according to parameter with this function:

$("#id_parameter").on('change', function(){
        var parameter = $("#id_parameter").val();
        if (parameter == 'niederschlag') {
            $("#id_start_date_year").val(2007);
        }
        if (parameter == 'bodentemperatur_5cm') {
            $("#id_start_date_year").val(1991);
        }

But this only change the value the user can see first. How can I change the possible years or range after the user select the parameter with jQuery?

Solution

There are 2 solutions to this that I can think of:

With views

First create the forms, the first that lets you choose the type, the second initiates the form for the options you make in "get_first_and_second_year":

# forms

class DataForm(forms.Form): 
    Parameter_CHOICES = [
        ('', 'Wähle ein Umweltvariable'),
        ('niederschlag', 'Niederschlag [L/m²]'),
        ('bodentemperatur_5cm', 'Bodentemperatur in 5cm Tiefe [°C]')
    ]   
    parameter = forms.ChoiceField(
        widget = forms.Select,
        choices = Parameter_CHOICES
    )

class DatePickForm(forms.Form):
    start_date = forms.DateField(label='Beginn:', widget=forms.SelectDateWidget())
    end_date = forms.DateField(label='Ende:', initial=datetime.now, widget=forms.SelectDateWidget())

    def __init__(self, *args, **kwargs):
        # get kwargs
        first_year = kwargs.pop('first_year', None)
        second_year = kwargs.pop('second_year', None)
        # super
        super(DatePickForm, self).__init__(*args, **kwargs)

        # initialize form fields
        self.fields['start_date'] = forms.DateField(
            label='Beginn:', 
            widget=forms.SelectDateWidget(
                years=list(range(first_year,second_year))
            )
        )
        self.fields['end_date'] = forms.DateField(
            label='Ende:', 
            widget=forms.SelectDateWidget(
                years=list(range(first_year,second_year))
            )
        )

Make the call for the page using different views:

# call in views


@login_required(login_url="/login/")
def date_form_view(request):
    form = DataForm(request.POST or None)
    if request.method == 'POST':
        #................................................................
        #    treat form
        #................................................................
        redirect('date_pick', form_choice=form_choice)
    # render with context 
    context = {'form': form}
    render(request, "", context)


def get_first_and_second_year(form_choice):
    # return first and second year depending on form choice
    match form_choice:
        case 'niederschlag':
            return first_year, second_year 
        case 'bodentemperatur_5cm':
            return first_year, second_year
        case _:
            return 0, 0


@login_required(login_url="/login/")
def date_form_view(request, form_choice):
    # dont forget to map url to this view with the argument
    
    first_year, second_year = get_first_and_second_year(form_choice)
    form = DatePickForm(request.POST or None, first_year=first_year, second_year=second_year)
    if request.method == 'POST':
        #................................................................
        #    treat form
        #................................................................        
        start_date = request.POST.get('start_date')
        # ...

    context = {'form': form}
    render(request, "", context)

With ajax (smoother interface, harder to code):

Ajax post/get calls explanation https://www.pluralsight.com/guides/work-with-ajax-django

Pass a json string to to the view that describes the different actions for each form_choice:

And prepend the html with the form for the form_choice.

Answered By – Ramon G.

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.