You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现表单二级联动:根据首个字段值过滤第二个字段选项

Django表单实现城市-商家二级联动方案

1. 补充关联模型定义

首先确保你有城市和商家的关联模型,示例如下(可根据实际需求调整):

from django.db import models
from .models import MyUser

class City(models.Model):
    name = models.CharField(max_length=100, unique=True)

    def __str__(self):
        return self.name

class Merchant(models.Model):
    name = models.CharField(max_length=200)
    city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='merchants')
    user = models.ForeignKey(MyUser, on_delete=models.RESTRICT)

    def __str__(self):
        return self.name

2. 修改表单类适配联动逻辑

以你现有ExcludedDateForm为基础,扩展支持城市-商家联动:

class ExcludedDateForm(ModelForm):
    class Meta:
        model = models.ExcludedDate
        exclude = ('user', 'recurring',)
        fields = ['city', 'merchant']  # 明确添加联动字段

    def __init__(self, user=None, **kwargs):
        super().__init__(**kwargs)
        if user:
            # 过滤当前用户可访问的城市
            self.fields['city'].queryset = models.City.objects.filter(merchants__user=user).distinct()
            
            # 初始化商家选项:根据当前城市过滤或设为空
            merchant_queryset = models.Merchant.objects.none()
            # 处理表单提交时的城市值
            if 'city' in self.data:
                try:
                    city_id = int(self.data.get('city'))
                    merchant_queryset = models.Merchant.objects.filter(city_id=city_id, user=user)
                except (ValueError, TypeError):
                    pass
            # 处理编辑场景的初始值
            elif self.instance.pk:
                merchant_queryset = self.instance.city.merchants.filter(user=user)
            
            self.fields['merchant'].queryset = merchant_queryset

3. 添加后端接口返回商家选项

新增视图用于异步获取指定城市的商家:

from django.http import JsonResponse
from django.views.decorators.http import require_GET
from django.contrib.auth.decorators import login_required
from .models import Merchant

@login_required
@require_GET
def get_merchants_by_city(request):
    city_id = request.GET.get('city_id')
    if not city_id:
        return JsonResponse({'options': []})
    
    try:
        merchants = Merchant.objects.filter(city_id=city_id, user=request.user).values('id', 'name')
        options = [{'value': m['id'], 'text': m['name']} for m in merchants]
        return JsonResponse({'options': options})
    except ValueError:
        return JsonResponse({'options': []})

在urls.py中添加路由:

from django.urls import path
from .views import get_merchants_by_city

urlpatterns = [
    # 其他路由...
    path('get-merchants/', get_merchants_by_city, name='get_merchants_by_city'),
]

4. 前端模板添加联动交互

在表单模板中加入JavaScript监听城市选择事件,动态更新商家选项:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">提交</button>
</form>

<script>
const citySelect = document.getElementById('id_city');
const merchantSelect = document.getElementById('id_merchant');

citySelect.addEventListener('change', function() {
    const cityId = this.value;
    merchantSelect.innerHTML = '<option value="">请选择商家</option>';
    
    if (!cityId) return;

    fetch(`{% url 'get_merchants_by_city' %}?city_id=${cityId}`)
        .then(res => res.json())
        .then(data => {
            data.options.forEach(opt => {
                const option = document.createElement('option');
                option.value = opt.value;
                option.textContent = opt.text;
                merchantSelect.appendChild(option);
            });
        })
        .catch(err => console.error('加载商家失败:', err));
});
</script>

核心逻辑说明

  • 权限过滤:所有城市、商家查询都关联当前用户,和你现有FilterByUserMixin的逻辑保持一致
  • 初始化兼容:覆盖新增、编辑两种场景的商家选项初始化
  • 无刷新联动:通过前端异步请求实现选项动态更新,提升用户体验

内容的提问来源于stack exchange,提问作者Den Silinskii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 20:42:43