Filter a Django form select element based on a previously selected element

前端 未结 2 1732
栀梦
栀梦 2021-02-03 11:28

Let\'s consider the following models

models.py

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


class CarModel(models.Model         


        
2条回答
  •  栀梦
    栀梦 (楼主)
    2021-02-03 12:06

    After hours and hours of research, without success, I decided to try to solve on my own. The solution that I found maybe don't be the best or the more elegant, but is working. (For download full Django project, click on this repo => https://github.com/Sidon/djfkf/.)


    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 cars on the fleet. The only fields that are will be recorded: Car (foreign key) and description. On the form, there will be one select element for brands that will work just only as a helper for to filter the car's combo box.


    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 a form for register cars, there are three fields: brand_select, car_select, and description. In addition, I defined two JSON attributes: 1) a dictionary whose keys are brands (strings) and values are lists of respective's cars and 2) A list of strings that represent the brands. Those two attributes will work as helpers for JS functions.


    views.py

    from django.shortcuts import render
    from .forms import RegCarForm
    from .models import *
    
    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 practically auto-explanatory. Assigns the Form to the car_form variable, render the template core/regcar.html and, after Post, make the validation of the form and save the data.


    regcar.html (template django)

    {% extends "base.html" %}
    
    {% block head %}
    {% endblock %}
    
    {% block content %}
        

    Registering cars on the fleet.
    (Populate one drop down based on selection in another)

    Change the contents of drop down Car based on the selection in dropdown Brand, using Django-forms + Javascritp

    {% csrf_token %} {{ car_form.as_p }}

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

    The template only just renders the form and load the script JS. Nothing else.


    Finally, the js script, that makes the hard work.

    {% block js %}
        
    {% endblock %}
    

    When the document is loaded, this script assigns the change event of brand_select (combo for selection of brand) to the function poplulateCar, assign the form's JASON attributes (cars and brands) to a JS variables and call the populateBrand function.

    Links:

    Full project in Django:
    https://github.com/Sidon/djfkf/

提交回复
热议问题