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

基于Django第一个模型类选择,展示第二个关联模型类字段列表的需求

实现Django中基于选择动态展示关联模型字段

咱们先把整个流程拆解清楚,从模型关联到前后端交互一步步来解决你的需求:

1. 完善模型关联定义

首先得确保两个模型的外键关联正确,这样才能通过Servico找到对应的ItemServico:

from django.db import models

class Servico(models.Model):
    desc_servico = models.CharField('Descrição', max_length=50, default='', blank=False)

    def __str__(self):
        return self.desc_servico  # 方便在表单里显示服务名称

class ItemServico(models.Model):
    desc_itemservico = models.CharField('Item Descrição', max_length=50, default='', blank=False)
    servico = models.ForeignKey(Servico, on_delete=models.CASCADE, related_name='itens')

    def __str__(self):
        return self.desc_itemservico

这里给外键加了related_name='itens',后续可以直接通过Servico实例.itens快速获取关联的子项。

2. 编写处理AJAX请求的视图

需要一个视图来接收前端传来的服务ID,返回对应的子项列表:

from django.http import JsonResponse
from .models import ItemServico

def get_itens_servico(request):
    servico_id = request.GET.get('servico_id')
    # 过滤出对应服务的子项,只返回需要的字段
    itens = ItemServico.objects.filter(servico_id=servico_id).values('id', 'desc_itemservico')
    return JsonResponse(list(itens), safe=False)

3. 配置路由映射

在app的urls.py中添加这个视图的路由:

from django.urls import path
from . import views

urlpatterns = [
    # 其他已有的路由...
    path('get-itens/', views.get_itens_servico, name='get_itens_servico'),
]

4. 前端实现动态更新逻辑

在模板里写表单和JavaScript,实现选择服务后自动加载对应的子项:

<form>
    <div class="form-group">
        <label for="servico">Serviço:</label>
        <select id="servico" name="servico" class="form-control">
            <option value="">Selecione um serviço</option>
            {% for servico in servicos %}
                <option value="{{ servico.id }}">{{ servico.desc_servico }}</option>
            {% endfor %}
        </select>
    </div>
    <div class="form-group mt-3">
        <label for="item_servico">Item do Serviço:</label>
        <select id="item_servico" name="item_servico" class="form-control">
            <option value="">Primeiro selecione um serviço</option>
        </select>
    </div>
</form>

<script>
// 监听服务选择框的变化事件
document.getElementById('servico').addEventListener('change', function() {
    const servicoId = this.value;
    const itemSelect = document.getElementById('item_servico');

    // 清空现有选项并显示加载状态
    itemSelect.innerHTML = '<option value="">Carregando...</option>';

    if (!servicoId) {
        itemSelect.innerHTML = '<option value="">Primeiro selecione um serviço</option>';
        return;
    }

    // 发送AJAX请求获取子项数据
    fetch(`{% url 'get_itens_servico' %}?servico_id=${servicoId}`)
        .then(response => response.json())
        .then(data => {
            // 重置选项并添加新的子项
            itemSelect.innerHTML = '<option value="">Selecione um item</option>';
            data.forEach(item => {
                const option = document.createElement('option');
                option.value = item.id;
                option.textContent = item.desc_itemservico;
                itemSelect.appendChild(option);
            });
        })
        .catch(error => {
            console.error('Erro ao carregar itens:', error);
            itemSelect.innerHTML = '<option value="">Erro ao carregar itens</option>';
        });
});
</script>

另外,渲染这个模板的视图需要把所有Servico实例传进去:

from django.shortcuts import render
from .models import Servico

def form_view(request):
    servicos = Servico.objects.all()
    return render(request, 'your_template.html', {'servicos': servicos})

5. 可选:后端表单验证(用Django Form类)

如果需要后端验证,可以定义表单类,确保提交时子项和服务匹配:

from django import forms
from .models import Servico, ItemServico

class ServicoItemForm(forms.Form):
    servico = forms.ModelChoiceField(queryset=Servico.objects.all(), label='Serviço')
    item_servico = forms.ModelChoiceField(queryset=ItemServico.objects.none(), label='Item do Serviço')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 如果是POST请求,根据选中的服务更新子项查询集
        if 'servico' in self.data:
            try:
                servico_id = int(self.data.get('servico'))
                self.fields['item_servico'].queryset = ItemServico.objects.filter(servico_id=servico_id)
            except (ValueError, TypeError):
                pass
        # 如果是编辑已有数据,初始化子项查询集
        elif self.instance.pk:
            self.fields['item_servico'].queryset = self.instance.servico.itens.all()

这样一套下来,就能实现选择Servico后动态展示对应ItemServico的需求啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:07:29