在Django里面,看看如何通过form来实现一个动态地select下拉框的效果。


首先看看静态的select的效果

models.py

class city(models.Model):
    name=models.CharField(max_length=32)
    #确保admin里面显示的是名字而不是object
    def __str__(self):
        return self.name

admin.py

from django.contrib import admin
from app01.models import city
admin.site.register(city)


然后在admin里面随便添加几条数据

wKiom1nMjtWAQpbYAABBE-fXDQA300.png


views.py

######################## Form #####################
from django import forms
from django.forms import widgets
from django.forms import fields
from app01 import models
from django.forms import ModelChoiceField
class FM(forms.Form):
#这里使用value_list是因为传递给choices的格式刚好是一个列表包括的元组格式
    city3=fields.ChoiceField(
        choices=models.city.objects.all().values_list('id', 'name'),
        widget=widgets.Select
      
    )
    
def fm(request):
    if request.method == "GET":
        obj=FM()
        return render(request,'fm.html',{'obj': obj})

效果如下

wKiom1nMj6zjxA25AAAGvjoUy_s822.png


这个时候,如果我在后台对city这个表进行了修改,刷新我的页面,显示的效果是不会改变的!只有当我重启整个Django,对应的数据才会在前台进行改变。


这是为什么呢?很简单,看看我们在class FM里面的定义,city3是这个类的静态字段,换句话说,这个字段在编译这个类的时候就初始化了,而当我们刷新页面,实例化对象的时候,这个静态字段的值并不会因为实例的不同而改变。那么为了改变对应的字段,解决方案就很明显了,要么在实例化以后的对象重新赋值,要么在实例化的过程中复制。这里我选择在实例化的过程中赋值,只需要自己重写一下init构造函数就行了。


修改代码:

注意super的使用,继承父类的init方法,然后再执行自己的赋值语句

city3=fields.ChoiceField(
       #反正要重新赋值,静态字段就没有必要赋值了
        choices=[]
)

def __init__(self,*args,**kwargs):
        super(FM,self).__init__(*args,**kwargs)
        self.fields['city3'].choices=models.city.objects.all().values_list('id','name')


这样就实现了动态地改变select内容的效果。


除此以外,Django本身也提供了一个内置的类来实现这个动态效果。

导入类,然后定义一个字段

from django.forms import ModelChoiceField
city4=forms.ModelChoiceField(
        queryset=models.city.objects.all(),
        empty_label='请选择城市',
)


效果如下


wKiom1nMkkiRD_jRAAAIzQIIvEo676.png