How to get value of django form within that same form before submission?

Question:

I’m creating a django form with 3 choice fields. I want the 3rd choice field (object field) to populate based on the first 2 choice fields. Boiling it down, I guess my question would be how do I get the values of the first 2 choice fields so I can use those values within the same form.py before submitting?

Here is what my forms.py looks like, which is currently giving me the error "maximum recursion depth exceeded":

class MyForm(forms.Form):
    season = forms.ChoiceField(
        widget=forms.Select(attrs={"class": "form-control test"}),
        label="season",
        choices=SEASON_CHOICES,
    )
    episode = forms.ChoiceField(
        widget=forms.Select(attrs={"class": "form-control"}), label="episode"
    )

    object = forms.ChoiceField(
        widget=forms.Select(attrs={"class": "form-control"}),
        label="object",
    )

    def __init__(self, *args, **kwargs):
        super(forms.Form, self).__init__(*args, **kwargs)
        form = MyForm()
        season = form.cleaned_data.get["season"]
        episode = form.cleaned_data.get["episode"]
        try:
            snow = Snowflake()
            snow_data = snow.query(
                f"""select * from modern_family"""
            )

            object_data = snow.query(
                f"""select * from {season}.{episode}"""
            )
            snow.close()
            self.fields["episode"].choices = [(sd[0], sd[0]) for sd in snow_data]
            self.fields["object"].choices = [(sd[0], sd[0]) for sd in object_data]
        except Exception as e:
            print(e)
Asked By: Shinhee Park

||

Answers:

What you are looking to do is create a ‘conditional’ form, where early elements dictate the format or presence of later elements.

Django doesn’t handle this use case out of the box, as views containing forms are created server-side and delivered to the client browser. Django has no default visibility over what happens on the client page, unfortunately. cleaned_data is what is produced by a submitted form, not one currently being filled out, so your approach won’t work as is.

Usually dynamic elements such as conditional forms are handled client side by javascript, as the elements on the page can be read before submission using onchange() or listener functions attached to the form elements.

There are a few approaches to try

  1. Split the form into two, and deliver a constructed third drop down in a separate view and form – for this you only need django

  2. Use HTMX or Ajax to make a call via javascript back to the server, then alter the third dropdown element appropriately based on the response. HTMX may be a good choice for this as you can deliver the new dropdown HTML directly from a django template. This is a good approach if you need to do server side calculations on what options should be available in the third dropdown.

  3. Use javascript alone to read the values of the first two dropdowns and amend the third dropdown. A good approach if all the info you need to edit the third dropdown is contained in the page.

Answered By: SamSparx