Come implementare due dropdown dipendenti l’una dall’altra in Django e jQuery

Ciao a tutti.

Con l’articolo di oggi vorrei mostrare come implementare due dropdown dipendenti l’una dall’altra usando Django e jQuery.

Supponiamo di avere una relazione 1-N tra marca di automobile e modello: nella prima dropdown vogliamo mostrare la lista delle marche; una volta selezionata una marca mostreremo nella seconda dropdown la lista dei modelli filtrati per quella marca.

Ipotizziamo di avere i modelli definiti così:

1
2
3
4
5
6
7
8
9
#models.py
class VehicleBrand(models.Model):
    description = models.CharField(max_length=100)
    code = models.SlugField(primary_key=True)

class VehicleModel(models.Model):
    description = models.CharField(max_length=100)
    code = models.SlugField(primary_key=True)
    brand = models.ForeignKey(VehicleBrand)

Iniziamo a definire il templatetag da includere nei nostri template:

1
2
3
4
5
6
7
8
9
10
11
#templatetags.py
from models import VehicleBrand

from django import template

register = template.Library()

@register.inclusion_tag("brand_model_select.html")
def brand_model_select():
    brand_list = VehicleBrand.objects.all()
    return {'brand_list' : brand_list}

Come possiamo vedere, il tag richiede un template html di supporto. Vediamo come è definito:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- brand_model_select.html -->
<form action="" method="get" accept-charset="utf-8">
    <select name="brand" id="brand">
        <option value="Z">Select a brand</option>
        {% for brand in brand_list %}
            <option value="{{ brand.code}}">{{ brand.description }}</option>
        {% endfor %}
    </select>
    <select name="model" id="model" disabled="true">
        <option>Select a model</option>
    </select>
</form>
<script>
    $(document).ready(
                     function() {
                         $("select#brand").change(function() {
                             if ($(this).val() == 'Z') {
                                 $("select#model").html("<option>Select a model</option>");
                                 $("select#model").attr('disabled', true);
                             }
                             else {
                                 var url = "/brand/" + $(this).val() + "/all_json_models";
                                 var brand = $(this).val();
                                 $.getJSON(url, function(models) {
                                     var options = '<option value="Z">Select a model</option>';
                                     for (var i = 0; i < models.length; i++) {
                                        options += '<option value="' + models[i].pk + '">' + models[i].fields['description'] + '</option>';
                                     }
                                     $("select#model").html(options);
                                     $("select#model option:first").attr('selected', 'selected');
                                     $("select#model").attr('disabled', false);
                                 });
                             }
                         });


                         $("select#model").change(function(vent) {
                             if ($(this).val() == -1) {
                                 return;
                             }
                             myAwesomeFunctionToCallWhenAModelIsSelected();
                         });
                     });
    }

</script>

Possiamo notare che non appena viene selezionato una marca, viene invocata una chiamata Ajax a questa url:
/brand/”selected_brand_code”/all_json_models

Dobbiamo definire dunque un’apposita view per poter intercettare questa url:

1
2
3
4
5
6
#views.py
def all_json_models(request, brand):
    current_brand = VehicleBrand.objects.get(code=brand)
    models = VehicleModel.objects.all().filter(brand=current_brand)
    json_models = serializers.serialize("json", models)
    return HttpResponse(json_models, mimetype="application/javascript")

e in urls.py:

1
2
3
#urls.py
...
(r'^brand/(?P<brand>[-\w]+)/all_json_models/$', 'all_json_models'),

Infine, il metodo javascript myAwesomeFunctionToCallWhenAModelIsSelected(); verrà scatenato una volta selezionato il nostro modello.

Tags: , ,


About Stefano

Stefano Mancini is a co-founder of DevInterface.

After graduating in Computer Science, he first specialized in Java/J2EE development by participating in several international projects in the pharmaceutical and banking ambits.

Enthusiast of agile development, like SCRUM for project management and eXtreme Programming for code writing, he then moved to dynamic languages like Ruby and Python.

About DevInterface

We are an information and communication technology agency. Our mission is to provide web application development, design services and communication strategies. We specialize in building web applications with modern and efficient frameworks.

Related Post

8 Responses to “Come implementare due dropdown dipendenti l’una dall’altra in Django e jQuery”

  1. Mario scrive:

    Great Post! i just need it!
    I think that there is small bug in views.py:

    Put VehicleBrand.objects.get() instead of VehicleBrand.get() and VehicleModel.objects.all().filter() instead if VehicleModel.all().filter()

  2. Stefano scrive:

    Thanks Mario.

    I’ve fixed the code :-)

  3. Andrea scrive:

    Appena usato proprio in un portale per auto usate,

    complimenti per il tuo lavoro

  4. Andrea scrive:

    dimenticavo…penso tu abbia dimenticato una } nello script

  5. benny scrive:

    This is just what I need.
    Anyway do you have a sample project files, I really new with Django. Thanks.

  6. J scrive:

    Very helpful. Thanks.

  7. Ani V scrive:

    Great doc ,Not works when Jquery transform applied..

Leave a Reply

Insert code beetween <code lang="ruby"> and </code>

Copyright 2012 DevInterface s.n.c.

DevInterface Blog is proudly powered by WordPress