Search code examples
djangoajaxdropdown

Django dependent dropdown with Ajax problems with ids


I am trying to implement a dependent dropdown. Vitor Freitas did this in his blog and I am basically following his solution. (A really cool blog with clear code which helped me a lot of times).

I have adopted it to my pages but it stuck exactly where the dropdown should be restricted. I am pretty sure that I messed up with the foreign key or with Ajax/javascript (as I have no clue about ajax+javascript.)

Maybe you see my 'basic' error and can help me. Would be thankful.

models.py

class Country(models.Model):
    name = models.CharField(max_length=3)
    def __str__(self):
        return self.name

class Provider(models.Model):
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name

class CustomerSubsidiary(models.Model):
    subCountry = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
    subName = models.CharField(max_length=50, blank=True)

urls.py

urlpatterns = [
    path('test', views.CustomerSubsidiaryListView.as_view(), name='CustomerSubsidiary_changelist'),
    path('test/add/', views.CustomerSubsidiaryCreateView.as_view(), name='CustomerSubsidiary_add'),
    path('test/<int:pk>/', views.CustomerSubsidiaryUpdateView.as_view(), name='CustomerSubsidiary_change'),
    path('ajax/load-provider/', views.load_provider, name='ajax_load_provider'),
]

views.py

def load_provider(request):
    country_id = request.GET.get('country')
    provider = Provider.objects.filter(country_id=country_id).order_by('name')
    return render(request, 'Customer/city_dropdown_list_options.html', {'provider': provider})

providerForm

class ProviderForm(forms.ModelForm):
    class Meta:
        model = CustomerSubsidiary
        fields = ('subName', 'subCountry', 'provider')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['provider'].queryset = Provider.objects.none()

customersubsidiary_form.html

{% extends 'base.html' %}

{% block content %}

  <h2>Provider Form</h2>

  <form method="post" id="providerForm" data-provider-url="{% url 'ajax_load_provider' %}" novalidate>
    {% csrf_token %}
    <table>
      {{ form.as_table }}
    </table>
    <button type="submit">Save</button>
    <a href="{% url 'CustomerSubsidiary_changelist' %}">Nevermind</a>
  </form>




  <script>
    $("#id_country").change(function () {
      var url = $("#providerForm").attr("data-provider-url");  
      var countryId = $(this).val();  

      $.ajax({                       
        url: url,                    
        data: {
          'country': countryId       
        },
        success: function (data) { 
          $("#id_provider").html(data);  
        }
      });

    });
  </script>

{% endblock %}

The jquery is loaded in the base.html.

city_dropdown_list_options.html

<option value="">-------</option>
{% for providers in provider %}
<option value="{{ providers.pk }}">{{ providers.name }}</option>
{% endfor %}

Solution

  • I saw in the source code of the page that the names for the Ids where wrong that means they did not match to views.py.

    In views.py it should be:

    def load_provider(request):
        country_id = request.GET.get('subCountry') #<-- change country to subCountry, that means the attribute name of the original class
    

    In the ajax-script change the id to #id_subCountry and change country to subCountry:

    <script>
        $("#id_subCountry").change(function () {
          var url = $("#providerForm").attr("data-provider-url");  // get the url of the `load_cities` view
          var subCountryId = $(this).val();  // get the selected country ID from the HTML input
    
          $.ajax({                       // initialize an AJAX request
            url: url,                    // set the url of the request (= localhost:8000/hr/ajax/load-cities/)
            data: {
              'subCountry': subCountryId       // add the country id to the GET parameters
            },
            success: function (data) {   // `data` is the return of the `load_cities` view function
              $("#id_provider").html(data);  // replace the contents of the city input with the data that came from the server
            }
          });
    
        });
      </script>