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

如何在Django forms中实现级联下拉菜单?

嘿,这个需求我之前在项目里实操过,用Django Forms配合前端AJAX完全能搞定,给你拆解下完整的实现步骤,分后端和前端两部分来捋:

后端实现步骤

1. 先搞定基础数据模型

首先得确保你的数据模型是关联好的,这是级联功能的基础:

# models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)

    def __str__(self):
        return self.title

class Chapter(models.Model):
    book = models.ForeignKey(Book, on_delete=models.CASCADE)
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

2. 定义表单类

创建一个Form,其中书籍下拉框正常渲染,章节下拉框初始留空,后续通过AJAX动态填充:

# forms.py
from django import forms
from .models import Book, Chapter

class BookChapterForm(forms.Form):
    book = forms.ModelChoiceField(queryset=Book.objects.all(), empty_label="请选择书籍")
    # 初始章节下拉框无数据,等待AJAX填充
    chapter = forms.ModelChoiceField(queryset=Chapter.objects.none(), empty_label="请先选择书籍")

3. 编写视图函数

需要两个核心视图:一个渲染表单页面,另一个作为AJAX接口返回对应章节数据:

# views.py
from django.shortcuts import render
from django.http import JsonResponse
from .models import Chapter
from .forms import BookChapterForm

def book_chapter_form(request):
    form = BookChapterForm()
    return render(request, 'book_chapter_template.html', {'form': form})

def get_chapters(request):
    # 从GET参数中获取选中的书籍ID
    book_id = request.GET.get('book_id')
    if book_id:
        # 查询该书籍对应的所有章节,返回id和名称
        chapters = Chapter.objects.filter(book_id=book_id).values('id', 'name')
        chapter_list = [{'id': item['id'], 'name': item['name']} for item in chapters]
        return JsonResponse({'chapters': chapter_list})
    # 未传入书籍ID时返回空列表
    return JsonResponse({'chapters': []})

4. 配置URL路由

把视图映射到具体URL,方便前端调用:

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('book-chapter/', views.book_chapter_form, name='book_chapter_form'),
    path('get-chapters/', views.get_chapters, name='get_chapters'),
]
前端实现步骤

在模板里渲染表单,并用jQuery监听下拉框变化,发送AJAX请求填充章节:

<!-- book_chapter_template.html -->
<!DOCTYPE html>
<html>
<head>
    <title>书籍章节选择</title>
    <!-- 引入jQuery,项目已有则无需重复引入 -->
    <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
</head>
<body>
    <form method="post">
        {% csrf_token %}
        {{ form.book.label_tag }} {{ form.book }}
        <br><br>
        {{ form.chapter.label_tag }} {{ form.chapter }}
        <br><br>
        <button type="submit">提交</button>
    </form>

    <script>
        $(document).ready(function() {
            const $bookSelect = $('#id_book');
            const $chapterSelect = $('#id_chapter');

            // 页面加载时默认禁用章节下拉框
            $chapterSelect.prop('disabled', true);

            // 监听书籍下拉框的变化事件
            $bookSelect.on('change', function() {
                const selectedBookId = $(this).val();
                
                if (selectedBookId) {
                    // 发送AJAX请求获取对应章节
                    $.ajax({
                        url: "{% url 'get_chapters' %}",
                        data: { 'book_id': selectedBookId },
                        dataType: 'json',
                        success: function(res) {
                            // 清空现有选项
                            $chapterSelect.empty();
                            // 添加默认提示
                            $chapterSelect.append('<option value="">请选择章节</option>');
                            // 循环添加章节选项
                            $.each(res.chapters, function(idx, chapter) {
                                $chapterSelect.append(`<option value="${chapter.id}">${chapter.name}</option>`);
                            });
                            // 启用章节下拉框
                            $chapterSelect.prop('disabled', false);
                        }
                    });
                } else {
                    // 未选中书籍时重置章节下拉框
                    $chapterSelect.empty();
                    $chapterSelect.append('<option value="">请先选择书籍</option>');
                    $chapterSelect.prop('disabled', true);
                }
            });
        });
    </script>
</body>
</html>
额外注意事项
  • 表单安全验证:提交表单时,后端要额外校验选中的章节确实属于选中的书籍,防止前端篡改数据:
    # 在book_chapter_form视图的POST处理中添加
    if request.method == 'POST':
        form = BookChapterForm(request.POST)
        if form.is_valid():
            selected_book = form.cleaned_data['book']
            selected_chapter = form.cleaned_data['chapter']
            if selected_chapter.book != selected_book:
                form.add_error('chapter', '该章节不属于选中的书籍')
            # 后续业务逻辑处理
    
  • 用户体验优化:可以在AJAX请求时添加loading状态提示,避免用户重复操作;如果有默认选中的书籍,页面加载时自动触发一次change事件填充章节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:45:04