过滤“下拉” django-form元素基于之前选择的值 [英] Filter a "drop-down" django-form element based on a value selected before

查看:114
本文介绍了过滤“下拉” django-form元素基于之前选择的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们考虑以下模型



models.py

 品牌(models.Model):
company_name = models.CharField(max_length = 100)


class CarModel(models.Model):
brand = models。 ForeignKey(品牌)
name = models.CharField(max_length = 100)


类FleetCars(models.Model):
model_car = models.Foreignkey(CarModel)

在django中最好的方法来解决这个问题?
假设一个表单(用于在FleetCars中插入)由两个选择元素组成,如下所示:



图像示例



 <!DOCTYPE html>< html>< head>< title>页面标题< / title>< / head>< body>< br />品牌:< select> ; < option value =Brand1> Brand1< / option> < option value =Brand2> Brand2< / option>< / select>< br />< br />模型:< select> < option value =Model1_B1> Model1_B1< / option> < option value =Model1_B2> Model1_B2< / option>< / select>< / body>< / html>  

div>



在这种情况下,我想要第二个选择中的选项取决于第一个选择的值,例如,如果用户选择Brand1为品牌第一选择,第二选择将被过滤,只有品牌是Brand1的汽车,这只是Model1_B1。



Obs。
我看到许多解决方案,其中有form.ModelChoiceField,但仅适用于编辑,因为用户不改变品牌。

解决方案

经过几个小时的研究,没有成功,我决定自己解决。我发现的解决方案可能不是最好的或更优雅的,但正在工作。 (要下载完整的Django项目,请点击此repo => https://github.com/Sidon/djfkf/ 。)






models.py

 从django.db导入模型

class品牌(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

在车队登记汽车。将记录的唯一字段:Car(外键)和描述。在表单上,​​将有一个品牌的选择元素,只能作为帮助者过滤汽车的组合框。






forms.py

  import json 
from django import forms
from .models import *

class RegCarForm(forms.ModelForm):

dcars = {}
list_cars = []
在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))

品牌= [品牌品牌Brand.objects.all() ]

brand_select = forms.ChoiceField(choices =(品牌,品牌)品牌品牌]))
car_select = forms.ChoiceField(choices =(list_cars))

品牌= json.dumps(品牌)
cars = json.dumps(dcars)

class Meta:
model = Fleet
fields =('brand_select','car_select','description')

RegCarForm是注册车的一种形式,有三个字段:brand_select,car_select和description。此外,我定义了两个JSON属性:1)一个字典,其键是品牌(字符串)和值是相应车辆的列表; 2)表示品牌的字符串列表。这两个属性将作为JS函数的助手。






views.py

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

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

如果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 '))
reg1.save()
else:
print('Invalid')

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

这个观点实际上是自动说明的。将表单分配给car_form变量,渲染模板核心/ regcar.html,并在Post后进行表单验证并保存数据。






regcar.html(template django)

  {%extendsbase.html%} 

{%block head%}
{%endblock%}

{%block content%}
< h1>在车队上注册汽车。 < br />(基于另一个中的选择来填充一个下拉)< / h1>
< p>根据下拉菜单中的选择更改下拉列表的内容品牌,使用Django-forms + Javascritp< / p>
< div class =select-style>
< form action =。方法= POST >
{%csrf_token%}
{{car_form.as_p}}
< p>< input type =submitvalue =注册汽车>< / p>
< / form>
< / div>
{%endblock%}

{%block js%}
{%includejs1.html%}
{%endblock%}

模板只是渲染表单并加载脚本JS。没有其他的东西。






最后,js脚本,这使努力工作。

  {%block js%} 
< script language =javascript>
$('#id_brand_select')。change(function(){populateCar(this)});
$('#id_description')。addClass('descript');
cars = {{car_form.cars |安全}}
品牌= {{car_form.brands |安全}};
populateBrand();
$(#id_car_select)。empty();
$(#id_car_select)。append('< option value =disabled selected>首先选择品牌< / option>');
函数populateBrand(){
$('#id_brand_select')。empty();
$(#id_brand_select)。append('< option value =disabled selected>选择您的选项< / option>');
$ .each(品牌,功能(v){
$('#id_brand_select')
.append($(< option>< / option>)
.attr(value,brands [v])
.text(brands [v]));
});
}

函数populateCar(event){
brand = $(#id_brand_select选项:选择)。
$(#id_car_select)。empty();
$(#id_car_select)。append('< option value =disabled selected>选择您的选项< / 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%}

当文档加载时,此脚本分配更改事件将brand_select(选择品牌的组合)添加到函数poplulateCar中,将表单的JASON属性(汽车和品牌)分配给JS变量并调用populateBrand函数。



链接:



Django中的完整项目:

https://github.com/Sidon/djfkf/


Let's consider the following models

models.py

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


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


Class FleetCars(models.Model):
    model_car = models.Foreignkey(CarModel)

What is the best way to solve this problem in django? Suppose a form (for insertions in FleetCars) consists of two select elements, like this:

Image example

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>

<br />Brand:
<select>
   <option value="Brand1">Brand1</option>
   <option value="Brand2">Brand2</option>
</select>
<br />
<br />Model:
<select>
   <option value="Model1_B1">Model1_B1</option>
   <option value="Model1_B2">Model1_B2</option>
</select>

</body>
</html>

In this case, I want the options in the second select depends on the value selected in the first, For example, if the user chose Brand1 for a Brand in the first select, the second select would be filtered with only cars whose Brand was Brand1, this is, only "Model1_B1".

Obs. I saw many solutions with forms.ModelChoiceField, but only works with edit and since the user do not change the brand.

解决方案

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 %}
    <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 just renders the form and load the script JS. Nothing else.


Finally, the js script, that makes 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, 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/

这篇关于过滤“下拉” django-form元素基于之前选择的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆