How to connect multiple chained dropdown with django-forms-dynamic

I have a form with counterparty, object and sections i connected them to each other with django-forms-dynamic package but object not connected to sections

Counterparty connected to object form but sections are not connected to object how can i fix that?

I guess that im wrong with 2 functions in forms.py: section_choices and initial_sections and they`re not connected to objects but dont know how to fix that

forms.py


class WorkLogForm(DynamicFormMixin, forms.ModelForm):

    def object_choices(form):
        contractor_counter = form['contractor_counter'].value()
        object_query = ObjectList.objects.filter(contractor_guid__in=[contractor_counter])
        return object_query

    def initial_object(form):
        contractor_counter = form['contractor_counter'].value()
        object_query = ObjectList.objects.filter(contractor_guid__in=[contractor_counter])
        return object_query.first()

    def section_choices(form):
        contractor_object = form['contractor_object'].value()
        section_query = SectionList.objects.filter(object=contractor_object)
        return section_query

    def initial_sections(form):
        contractor_object = form['contractor_object'].value()
        section_query = SectionList.objects.filter(object=contractor_object)
        return section_query.first()

    contractor_counter = forms.ModelChoiceField(
        label='Контрагент',
        queryset=CounterParty.objects.none(),
        initial=CounterParty.objects.first(),
        empty_label='',
    )

    contractor_object = DynamicField(
        forms.ModelChoiceField,
        label='Объект',
        queryset=object_choices,
        initial=initial_object,
    )

    contractor_section = DynamicField(
        forms.ModelMultipleChoiceField,
        label='Раздел',
        queryset=section_choices,
        initial=initial_sections,
    )

views.py

@login_required
def create_work_log(request):
    if request.method == 'POST':
        form = WorkLogForm(request.POST, user=request.user)
        if form.is_valid():
            work_log = form.save(commit=False)
            work_log.author = request.user
            work_log = form.save()
            messages.success(request, 'Данные занесены успешно', {'work_log': work_log})
            return redirect('create_worklog')
        else:
            messages.error(request, 'Ошибка валидации')
            return redirect('create_worklog')
  
        form = WorkLogForm(user=request.user, initial=initial)

    return render(request, 'contractor/create_work_log.html', {'form': form})


def contractor_object(request):
    form = WorkLogForm(request.GET, user=request.user)
    return HttpResponse(form['contractor_object'])


def contractor_section(request):
    form = WorkLogForm(request.GET, user=request.user)
    return HttpResponse(form['contractor_section'])

To connect multiple chained dropdowns in Django using HTMX, you can make use of the following steps :

  1. Create Django views that return the data for each dropdown based on the selected value of the previous dropdown.

  2. Create HTML templates for each dropdown and include the HTMX attributes hx-post and hx-trigger to handle the interactions between the dropdowns.

  3. In the HTML templates, bind the dropdown's hx-post attribute to the URL of the corresponding Django view.

  4. In the same templates, bind the dropdown's hx-trigger attribute to the ID of the previous dropdown, so that it triggers the request when its value changes.

  5. In the Django views, use the render_to_response function to return the HTML for the next dropdown.

Here's a sample code snippet for the views :

from django.shortcuts import render_to_response

def get_dropdown2_data(request):
    # Get the selected value of dropdown 1
    dropdown1_value = request.POST.get('dropdown1_value')
    # Generate data for dropdown 2 based on the selected value of dropdown 1
    dropdown2_data = [{'value': 1, 'text': 'Option 1'},
                      {'value': 2, 'text': 'Option 2'}]
    return render_to_response('dropdown2.html', {'dropdown2_data': dropdown2_data})

def get_dropdown3_data(request):
    # Get the selected value of dropdown 2
    dropdown2_value = request.POST.get('dropdown2_value')
    # Generate data for dropdown 3 based on the selected value of dropdown 2
    dropdown3_data = [{'value': 3, 'text': 'Option 3'},
                      {'value': 4, 'text': 'Option 4'}]
    return render_to_response('dropdown3.html', {'dropdown3_data': dropdown3_data})

Here's a sample code snippet for the HTML templates :

<!-- dropdown1.html -->
<select id="dropdown1">
  <option value="">-- Select --</option>
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
</select>

<!-- dropdown2.html -->
<select id="dropdown2" hx-post="/get_dropdown2_data/" hx-trigger="#dropdown1">
  <option value="">-- Select --</option>
  {% for option in dropdown2_data %}
    <option value="{{ option.value }}">{{ option.text }}</option>
  {% endfor %}
</select>

<!-- dropdown3.html -->
<select id="dropdown3" hx-post="/get_dropdown3_data/" hx-trigger="#dropdown2">
  <option value="">-- Select --</option>
  {% for option in dropdown3_data %}
    <option value="{{ option.value }}">{{ option.text }}</option>
  {% endfor %}
</select>

This may not be an answer you want but I use HTMX for these things. Here is a link to their example for this.

https://htmx.org/examples/value-select/

There is also a package plugin called Django-htmx.

You may need to learn HTMX but it is a mature technology, rather simple and reliable. I am unfamiliar with Django-forms-dynamic

Back to Top