Django表单实现字段联动过滤:选城市后过滤关联字段
Django表单实现城市与对象名称的联动过滤
核心需求是实现「选择城市后,自动过滤对象名称下拉选项」,这需要后端提供数据接口配合前端AJAX完成,分以下几步操作:
1. 模型优化(可选但建议)
如果ArkiTwoObject是通过一对一关联ArkiOneObject,先给ArkiOneObject加唯一约束,避免同一城市下出现重复的对象名称——否则一对一关联会产生数据冲突:
class ArkiOneObject(models.Model): city = models.CharField(max_length=100, verbose_name="城市") nameobject = models.CharField(max_length=200, verbose_name="对象名称") class Meta: unique_together = ('city', 'nameobject') # 确保同一城市的对象名称唯一 class ArkiTwoObject(models.Model): arki_one = models.OneToOneField(ArkiOneObject, on_delete=models.CASCADE, verbose_name="关联对象") # 你的其他业务字段...
如果是ArkiTwoObject单独存储city和nameobject字段(不关联ArkiOneObject),模型可保持原样,但需自行承担数据冗余的风险。
2. 定义联动表单
创建FormTwo时,单独拆分city和nameobject为下拉字段,方便后续联动逻辑处理:
from django import forms from .models import ArkiOneObject, ArkiTwoObject class FormTwo(forms.ModelForm): city = forms.ChoiceField(choices=[], required=True, verbose_name="城市") nameobject = forms.ChoiceField(choices=[], required=True, verbose_name="对象名称") class Meta: model = ArkiTwoObject fields = ['city', 'nameobject', ...] # 补充你的其他业务字段 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 初始化城市选项:去重获取所有城市 self.fields['city'].choices = [(city, city) for city in ArkiOneObject.objects.values_list('city', flat=True).distinct()] # 编辑页面初始化:加载已选城市对应的对象名称 if self.instance.pk: target_arki = self.instance.arki_one self.fields['city'].initial = target_arki.city name_options = [(obj.nameobject, obj.nameobject) for obj in ArkiOneObject.objects.filter(city=target_arki.city)] self.fields['nameobject'].choices = name_options self.fields['nameobject'].initial = target_arki.nameobject
3. 后端AJAX接口实现
编写视图函数,接收选中的城市参数,返回该城市下的所有对象名称:
from django.http import JsonResponse from .models import ArkiOneObject def get_nameobjects_by_city(request): selected_city = request.GET.get('city') if not selected_city: return JsonResponse({'choices': []}) # 过滤并提取目标城市的对象名称 name_list = ArkiOneObject.objects.filter(city=selected_city).values_list('nameobject', flat=True) # 转换为下拉框所需的选项格式 choices = [(name, name) for name in name_list] return JsonResponse({'choices': choices})
在urls.py中配置接口路由:
from django.urls import path from .views import get_nameobjects_by_city, form_two_view # 替换为你的表单视图 urlpatterns = [ path('form-two/', form_two_view, name='form_two'), path('get-nameobjects/', get_nameobjects_by_city, name='get_nameobjects'), ]
4. 前端JS联动逻辑
在表单模板中添加JavaScript,监听城市下拉框的变化,通过AJAX更新对象名称选项:
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form> <script> document.addEventListener('DOMContentLoaded', function() { const citySelect = document.getElementById('id_city'); const nameSelect = document.getElementById('id_nameobject'); // 监听城市选择事件 citySelect.addEventListener('change', function() { const city = this.value; // 清空对象名称选项 nameSelect.innerHTML = '<option value="">请选择对象名称</option>'; if (!city) return; // 发送AJAX请求获取对应城市的对象名称 fetch(`{% url 'get_nameobjects' %}?city=${encodeURIComponent(city)}`) .then(res => res.json()) .then(data => { // 动态添加新选项 data.choices.forEach(item => { const option = document.createElement('option'); option.value = item[0]; option.textContent = item[1]; nameSelect.appendChild(option); }); }) .catch(err => console.log('加载对象名称失败:', err)); }); // 编辑页面自动触发一次选择事件,加载已选城市的对象名称 if (citySelect.value) { citySelect.dispatchEvent(new Event('change')); } }); </script>
5. 表单提交处理
在表单视图中,将选中的城市和对象名称关联到ArkiOneObject实例,再保存ArkiTwoObject:
def form_two_view(request): if request.method == 'POST': form = FormTwo(request.POST) if form.is_valid(): city = form.cleaned_data['city'] name = form.cleaned_data['nameobject'] # 获取对应的ArkiOneObject实例 arki_one_instance = ArkiOneObject.objects.get(city=city, nameobject=name) # 保存ArkiTwoObject并关联实例 arki_two = form.save(commit=False) arki_two.arki_one = arki_one_instance arki_two.save() # 跳转至成功页面或添加提示 return redirect('your_success_url') else: form = FormTwo() return render(request, 'your_form_template.html', {'form': form})
如果是ArkiTwoObject直接存储city和nameobject字段,直接调用form.save()即可,无需额外关联处理。
内容的提问来源于stack exchange,提问作者Денис
相关产品推荐
相关产品推荐

