最终实现效果:
![django多级联动效果预览](http://www.tingcheba.com/wp-content/uploads/2011/10/2011-10-30-15-07-44.gif)
类似 国家 -> 省 -> 市 这样的多级分类联动下拉列表在各种项目中都经常用到,但是放狗搜了半天也没有一套Django完整的解决教程,最接近的是 芝麻问答 ,但也只是在模型上简单描述了思路,离最终的完成还有一段距离。所以,只有自己动手了…
思路:
普通Html页面下多级联动的实现是通过对<OPTION>进行动作绑定,一旦发生数据改变就对子类别的下拉列表进行更新。Django于此相异的地方主要在于后台数据的传递,我们只要建立一个分类数据读取接口,然后将从数据库中读出的相关值生成JSON格式传递到前台页面即可。
在数据库的设计上,我想尽量简单,只是用三个字段来实现无线分类,分别是id,name,pid(父级分类ID);另外由于分类并非经常更改,但要经常读取,为了避免不必要的数据库开销,我将每次更新后的分类数据生成一个静态JS格式文件供前台读取。
实现代码:
首先是选择前台页面的JS联动代码,感谢“YAODAYIZI”提供的脚本,具体如下:
1.表现层Html页面(category_list.html):
05 |
Django Learning 下拉列表多级联动选择 |
07 |
< meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" /> |
08 |
< script language = "javascript" > |
09 |
function Dlist(array) { |
13 |
this.subSelectChange = function(selectName1, selectName2) { |
14 |
var obj1 = document.all[selectName1]; |
15 |
var obj2 = document.all[selectName2]; |
16 |
var objName = this.toString(); |
18 |
obj1.onchange = function() { |
19 |
me.optionChange(this.options[this.selectedIndex].value, obj2.id) |
22 |
this.firstSelectChange = function(indexName, selectName) { |
23 |
this.obj = document.all[selectName]; |
24 |
this.indexName = indexName; |
25 |
this.optionChange(this.indexName, this.obj.id) |
27 |
this.optionChange = function(indexName, selectName) { |
28 |
var obj1 = document.all[selectName]; |
31 |
obj1.options[0] = new Option("请选择", ''); |
32 |
for (var i = 0; i < this.array.length ; i++) { |
33 |
if (this.array[i][1] == indexName) { |
34 |
obj1.options[obj1.length] = new Option(this.array[i][2], this.array[i][0]) |
43 |
< a href = "?mode=reset" > |
46 |
< form name = "form1" method = "post" > |
47 |
< SELECT ID = "s1" NAME = "s1" size = "10" > |
51 |
< SELECT ID = "s2" NAME = "s2" size = "10" > |
55 |
< SELECT ID = "s3" NAME = "s3" size = "10" > |
60 |
< script type = "text/javascript" src = "/static/js/category_data.js" > |
62 |
< script type = "text/javascript" > |
63 |
var liandong = new Dlist(array) liandong.firstSelectChange("0", "s1"); |
64 |
liandong.subSelectChange("s1", "s2"); |
65 |
liandong.subSelectChange("s2", "s3"); |
2.Model类
1 |
class Category(models.Model): |
2 |
c_name = models.CharField(max_length = 20 ,help_text = "类别名称" ) |
3 |
c_father = models.IntegerField(max_length = 4 ,default = 0 ,help_text = "父级类别ID" ) |
4 |
c_hidden = models.BooleanField(default = 0 ,blank = True ) |
7 |
return (u '%d,%d,%s' ) % ( self . id , self .c_father, self .c_name) |
3. 根据数据库生成的JS数据文件(category_data.js):
01 |
var array= new Array(); |
02 |
array[0]= new Array( '1' , '0' , '罗莱' ) |
03 |
array[1]= new Array( '2' , '0' , '优家' ) |
04 |
array[2]= new Array( '3' , '0' , '宝缦' ) |
05 |
array[3]= new Array( '4' , '0' , '其他' ) |
06 |
array[4]= new Array( '5' , '1' , '芯类' ) |
07 |
array[5]= new Array( '6' , '1' , '家居类' ) |
08 |
array[6]= new Array( '7' , '5' , '被芯' ) |
09 |
array[7]= new Array( '8' , '5' , '枕芯' ) |
10 |
array[8]= new Array( '9' , '2' , '新经典' ) |
11 |
array[9]= new Array( '10' , '2' , '新优雅' ) |
4. 根据数据库生成的category_data的办法(view.py):< /strong>
02 |
def category_manage(request): |
03 |
if request.GET.has_key( 'mode' ): |
04 |
mode = request.GET[ 'mode' ] |
06 |
jfile = codecs. open ( 'static/js/category_data.js' , 'w' , 'utf-8' ) |
07 |
jfile.write( "var array=new Array();\n" ) |
08 |
clist = Category.objects. all () |
10 |
jfile.write ( "array[%d]=new Array('%d','%d','%s')\n" % (c. id - 1 ,c. id ,c.c_father,c.c_name)) |
12 |
return render_to_response( 'category.html' , locals ()) |
到这里已经完成的七七八八了,然后去url.py下配置好相关路径就可以运行了,如果你希望直接从数据库中读取或者希望和Form类紧密关联,修改起来也会比较容易,有时间的话下次我再另外发一篇练习文章。
希望以上的内容对你有所帮助。