Dropdown dependent on each other

5

I'm using a function from this site:

link

The function works perfectly, when I select an option in a dropdown, the 2nd DropDown already brings me what I want, the only problem is after clicking the submit button that does not bring me the selected fields of these dropdowns, I believe I'm not sure how to use the POST method in javascript. I do not have much knowledge in javascript / ajax. Here's a small part of an example of what I'm trying to do:

Model

class Regiao(models.Model):    
    marca=models.IntegerField('Marca', null=True, blank=True,)
    cor=models.ForeignKey('cor.Cor', verbose_name=u'Cores', null=True, blank=True,)

Form

class RegiaoForm(forms.ModelForm):
    class Meta:
        model=Regiao
    fields=['marca', 'cor']

Views

form = RegiaoForm(request.POST or None)

    if form.is_valid():
        saveMarca = request.POST['marca']

        return redirect('apps.past.views.marcas')

marcas=Marca.objects.all()

return render_to_response('marca.html', {'form':form, 'marcas':marcas}, context_instance=RequestContext(request))

def log_getdetails(request):
    selected_marca = ""

    marca_name = request.GET['cnt']

    result_set = []
    all_cores = []

    marca_name = marca_name.split()
    marca_name = str(marca_name[2])

    selected_marca = Marca.objects.get(name=marca_name)
    all_cores = selected_marca.cor_set.all()
    for cor in all_cores:
        result_set.append({'name': cor.name})

    return HttpResponse(json.dumps(result_set), mimetype='application/json', content_type='application/json')

Template

JAVASCRIPT

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script><scripttype="text/javascript" src="http://yourjavascript.com/7174319415/script.js"></script><script>$(document).ready(function(){$('select#selectmarcas').change(function(){varoptionSelected=$(this).find("option:selected");
                 //var valueSelected  = $(this.result).find("option:selected");
                 var marca_name   = optionSelected.text();


                 data = {'cnt' : marca_name};
                 ajax('/getdetails',data,function(result){
                        console.log(result);
                        $("#selectcores option").remove();
                        $("#selectcores").append('<option>'+'TODOS'+'</option>');
                        for (var i = result.length - 1; i >= 0; i--) {
                            $("#selectcores").append('<option>'+ result[i].name +'</option>');
                        };

                     });
             });
        });
</script>

HTML

{% block content %}
    <form class="form-horizontal" method="post">
        {% csrf_token %}
            {% load add_attr %}
<select class="form-control" name="selectmarcas" id="selectmarcas" >
                    <option value="">TODAS</option>
                    {% for marca in marcas %}
                        <option value="{{marca.id }}">{{ marca.name }}</option>
                    {% endfor %}
                </select>
                </div>
            </div>
            <br/>
            <div class="row {% if form.cor.errors %}has-error{% endif %}">
            <label class="col-md-2 control-label" for="{{form.cor.auto_id }}">
                {{form.cor.label }}
            </label>
                <div>
                    <select class="form-control" name ="selectcores" id="selectcores">
                        <option value="">TODAS</option>
                    </select>
           <button type="submit" class="btn btn-primary">Salvar</button>
</form>
{% endblock %}

What I need is that in addition to making a dropdown dependent on the other is to be able to save the information that I selected after giving the submit. I'm sorry if I put a lot of information, but I'm trying to clarify my question.

    
asked by anonymous 25.06.2016 / 05:02

1 answer

1

I had a similar problem and after hours and hours of searching, I decided to implement my version. I will explain briefly here, I have the full and functional version available in github, see the links at the end of this answer.

Consider for this answer a register of vehicles in a fleet, where we have 3 tables: Brands, Car Models and Fleet.

See the html + javascript version below, and then the explanation of the solution in Django:

// By Sidon | 2017
// Fiddle version: https://jsfiddle.net/Sidon/6m1nf0zu/62/
$(document).ready(function(){

    $('#brand').change(function() {populateCar()});  
  
    var ford = ['Fiesta', 'Focus', 'Fusion', 'Taurus', 'Mustang'];
    var vw = ['Passat', 'Tiguan', 'Golf', 'Jetta', 'Up']
    var fiat = ['Punto', '500', '500 City', 'Panda', 'Doblô']
    var cars =  {'Ford': ford, 'Volks': vw, 'Fiat': fiat}
    var brands = ['Ford','Fiat', 'Volks']
    populateBrand()
  
  
    function populateBrand() {
        $("#brand").empty();
        $("#brand").append('<option value="" disabled selected>Select your option</option>');
        $.each(brands, function(v) {
            $('#brand')
                .append($("<option></option>")
                .attr("value", brands[v])
                .text(brands[v]));
        })
    }


    function populateCar(event) {
        brand = $("#brand option:selected" ).text();
        $("#car").empty();
        for (let [k, v] of Object.entries(cars)) {
            if(k==brand) {
                for (car in cars[brand]) {
                    var opt = document.createElement("option");
                     $('#car')
                         .append($("<option></option>")
                         .attr("value", cars[brand][car])
                         .text(cars[brand][car]));
                }
            };
        }
    }
 
});
body {
  margin-left: 30px
}

.select-style {
    width: 320px;
    height: 100%;
    border-radius: 3px;
}

.select-style select {
    padding: 5px 8px;
    width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><!--BySidon|2017Fiddleversion:https://jsfiddle.net/Sidon/6m1nf0zu/62/--><body><divclass="select-style">
    <br />Brand:
    <select required id="brand">
    </select>

    <br />  
    <br />Car:     
    <select id="car" >
        <option value=""> </option>
    </select>
  </div>
      
</body>
  

From this point on, the description of the solution in Django

models.py

from django.db import models

class Brand(models.Model):
    company_name = models.CharField(max_length=100)

    def __str__(self):
        return self.company_name


class Car(models.Model):
    brand = models.ForeignKey(Brand)
    name = models.CharField(max_length=100)

    def brand_name(self):
        return self.brand.company_name

    def __str__(self):
        return self.name


class Fleet(models.Model):
    car = models.ForeignKey(Car)
    description = models.CharField(max_length=100)

    def car_name(self):
        return self.car.name

    def brand(self):
        return self.car.brand.company_name

    def __str__(self):
        return self.description

The goal is to register the cars in the fleet. Note that only the car (foreign key) and description fields will actually be written. In the form there will be a combo that will use the brand class, only to filter the next combo (the models of the cars).

forms.py

import json
from django import forms
from .models import *

class RegCarForm(forms.ModelForm):

    dcars = {}
    list_cars = []
    for car in Car.objects.all():
        if car.brand.company_name in dcars:
            dcars[car.brand.company_name].append(car.name)
        else:
            dcars[car.brand.company_name] = [car.name]
        list_cars.append((car.name,car.name))

    brands = [str(brand) for brand in Brand.objects.all()]

    brand_select = forms.ChoiceField(choices=([(brand, brand) for brand in brands]))
    car_select = forms.ChoiceField(choices=(list_cars))

    brands = json.dumps(brands)
    cars = json.dumps(dcars)

    class Meta:
        model = Fleet
        fields = ('brand_select', 'car_select', 'description',)
RegCarForm is the Form for the registration of cars, there are 3 fields: brand_select, car_select, and description, I have also created 2 JSON attributes: 1) A dictionary whose keys are the marks and values are lists of their respective models. expensive, and 2) a list of brands. These two attributes will serve as auxiliary variables for the JS functions.

views

from django.shortcuts import render
from .forms import RegCarForm
from .models import *

# Create your views here.

def regcar(request):
    if request.method == 'POST':
        car_form = RegCarForm(data=request.POST)

        if car_form.is_valid():
            cdata = car_form.cleaned_data.get
            car_selected = Car.objects.filter(name=cdata('car_select'))
            reg1 = Fleet(car_id=car_selected[0].id, description=cdata('description'))
            reg1.save()
        else:
            print ('Invalid')

    else:
        car_form = RegCarForm()
    return render(request, 'core/regcar.html', {'car_form': car_form})

The view is self-explanatory, assigns the form to the variable car_form, renders the template core / regcar.html and, after the Post, validates the form and saves the data.

regcar.html (template django)

{% extends "base.html" %}

{% block head %}
{% endblock %}

{% block content %}
    <h1>Registering cars on the fleet. <br />(Populate one drop down based on selection in another)</h1>
    <p>Change the contents of drop down Car based on the selection in dropdown Brand, using Django-forms + Javascritp</p>
    <div class="select-style">
        <form action="." method="post">
            {% csrf_token %}
            {{ car_form.as_p }}
            <p><input type="submit" value="Register a car"></p>
        </form>
    </div>
{% endblock %}

{% block js %}
    {% include "js1.html" %}
{% endblock %}

The template only renders the form and loads the JS script.

Finally, the JS script. What does the hard work.

{% block js %}
    <script language="javascript">
        $('#id_brand_select').change(function() {populateCar(this)});
        $('#id_description').addClass('descriptions');
        cars = {{ car_form.cars | safe }}
        brands = {{ car_form.brands | safe}};
        populateBrand();
        $("#id_car_select").empty();
        $("#id_car_select").append('<option value="" disabled selected>First select a brand</option>');

        function populateBrand() {
            $('#id_brand_select').empty();
            $("#id_brand_select").append('<option value="" disabled selected>Select your option</option>');
            $.each(brands, function(v) {
                $('#id_brand_select')
                    .append($("<option></option>")
                    .attr("value", brands[v])
                    .text(brands[v]));
            });
        }

        function populateCar(event) {
            brand = $("#id_brand_select option:selected").text();
            $("#id_car_select").empty();
            $("#id_car_select").append('<option value="" disabled selected>Select your option</option>');
            for (let [b, bcars] of Object.entries(cars)) {
                if (b == brand) {
                    //alert(b);
                    for (car in bcars) {
                        $('#id_car_select')
                            .append($("<option></option>")
                                .attr("value", bcars[car])
                                .text(bcars[car]));
                    }
                }
            }
        }
    </script>
{% endblock %}

When the document is loaded, the script assigns the change event of the element brand_select (combo for selecting the tags) to the populateCar function, creates two JS variables by assigning the values of the form's JSON attributes (cars and brands) and calls the populateBrand function.

Links:

Complete project in django:
link

Codepen Version:
link

Fiddle Version:
link

This question in English

    
28.03.2017 / 20:14