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

在Django中实现两组联动下拉框的小型CRUD系统开发请求

Django 实现带联动字段的CRUD系统

一、模型定义

先创建关联模型与主记录模型,处理国家-州、产品类型-产品名的关联逻辑:

# models.py
from django.db import models

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

    def __str__(self):
        return self.name

class State(models.Model):
    country = models.ForeignKey(Country, on_delete=models.CASCADE, related_name='states')
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class ProductType(models.Model):
    name = models.CharField(max_length=50, unique=True)  # 对应蔬菜、水果选项

    def __str__(self):
        return self.name

class ProductName(models.Model):
    product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE, related_name='products')
    name = models.CharField(max_length=100)  # 对应卷心菜、土豆、苹果、橙子

    def __str__(self):
        return self.name

class Record(models.Model):
    STATUS_CHOICES = [
        ('Testing1', 'Testing1'),
        ('Testing2', 'Testing2'),
        ('Testing3', 'Testing3'),
    ]
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    state = models.ForeignKey(State, on_delete=models.CASCADE)
    product_type = models.ForeignKey(ProductType, on_delete=models.CASCADE)
    product_name = models.ForeignKey(ProductName, on_delete=models.CASCADE)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES)
    datetime = models.DateTimeField()

    def __str__(self):
        return f"{self.product_name.name} - {self.status}"

二、视图与AJAX接口

编写CRUD视图处理数据操作,同时添加两个AJAX接口实现下拉框联动:

# views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import JsonResponse
from .models import Country, State, ProductType, ProductName, Record
from .forms import RecordForm

def record_list(request):
    records = Record.objects.all()
    return render(request, 'record_list.html', {'records': records})

def record_create(request):
    if request.method == 'POST':
        form = RecordForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('record_list')
    else:
        form = RecordForm()
    return render(request, 'record_form.html', {'form': form})

def record_update(request, pk):
    record = get_object_or_404(Record, pk=pk)
    if request.method == 'POST':
        form = RecordForm(request.POST, instance=record)
        if form.is_valid():
            form.save()
            return redirect('record_list')
    else:
        form = RecordForm(instance=record)
    return render(request, 'record_form.html', {'form': form})

def record_delete(request, pk):
    record = get_object_or_404(Record, pk=pk)
    if request.method == 'POST':
        record.delete()
        return redirect('record_list')
    return render(request, 'record_confirm_delete.html', {'record': record})

# 根据国家ID获取对应州列表
def get_states(request):
    country_id = request.GET.get('country_id')
    states = State.objects.filter(country_id=country_id).values('id', 'name')
    return JsonResponse(list(states), safe=False)

# 根据产品类型ID获取对应产品名列表
def get_product_names(request):
    product_type_id = request.GET.get('product_type_id')
    products = ProductName.objects.filter(product_type_id=product_type_id).values('id', 'name')
    return JsonResponse(list(products), safe=False)

三、表单定义

创建ModelForm简化表单渲染,同时指定日期时间输入格式:

# forms.py
from django import forms
from .models import Record

class RecordForm(forms.ModelForm):
    class Meta:
        model = Record
        fields = ['country', 'state', 'product_type', 'product_name', 'status', 'datetime']
        widgets = {
            'datetime': forms.DateTimeInput(
                format='%m-%d-%Y %H:%M:%S',
                attrs={'type': 'text', 'placeholder': 'mm-dd-yyyy hh:mm:ss'}
            ),
        }

四、URL配置

配置路由映射CRUD操作与AJAX接口:

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

urlpatterns = [
    path('', views.record_list, name='record_list'),
    path('create/', views.record_create, name='record_create'),
    path('update/<int:pk>/', views.record_update, name='record_update'),
    path('delete/<int:pk>/', views.record_delete, name='record_delete'),
    path('get-states/', views.get_states, name='get_states'),
    path('get-product-names/', views.get_product_names, name='get_product_names'),
]

五、模板与前端联动逻辑

编写表单模板,通过JavaScript实现下拉框联动,同时处理编辑页面的初始值回显:

<!-- templates/record_form.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Record Form</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
        $(document).ready(function() {
            // 国家-州联动
            $('#id_country').change(function() {
                var countryId = $(this).val();
                $.ajax({
                    url: '/get-states/',
                    data: {'country_id': countryId},
                    dataType: 'json',
                    success: function(data) {
                        $('#id_state').empty();
                        $.each(data, function(index, item) {
                            $('#id_state').append('<option value="' + item.id + '">' + item.name + '</option>');
                        });
                    }
                });
            });

            // 产品类型-产品名联动
            $('#id_product_type').change(function() {
                var productTypeId = $(this).val();
                $.ajax({
                    url: '/get-product-names/',
                    data: {'product_type_id': productTypeId},
                    dataType: 'json',
                    success: function(data) {
                        $('#id_product_name').empty();
                        $.each(data, function(index, item) {
                            $('#id_product_name').append('<option value="' + item.id + '">' + item.name + '</option>');
                        });
                    }
                });
            });

            // 编辑页面初始化联动数据
            {% if form.instance.pk %}
                $('#id_state').empty();
                $.ajax({
                    url: '/get-states/',
                    data: {'country_id': $('#id_country').val()},
                    dataType: 'json',
                    success: function(data) {
                        $.each(data, function(index, item) {
                            var selected = item.id == {{ form.instance.state.id }} ? 'selected' : '';
                            $('#id_state').append('<option value="' + item.id + '" ' + selected + '>' + item.name + '</option>');
                        });
                    }
                });

                $('#id_product_name').empty();
                $.ajax({
                    url: '/get-product-names/',
                    data: {'product_type_id': $('#id_product_type').val()},
                    dataType: 'json',
                    success: function(data) {
                        $.each(data, function(index, item) {
                            var selected = item.id == {{ form.instance.product_name.id }} ? 'selected' : '';
                            $('#id_product_name').append('<option value="' + item.id + '" ' + selected + '>' + item.name + '</option>');
                        });
                    }
                });
            {% endif %}
        });
    </script>
</head>
<body>
    <h1>{% if form.instance.pk %}编辑{% else %}新建{% endif %}记录</h1>
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">保存</button>
    </form>
    <a href="{% url 'record_list' %}">返回列表</a>
</body>
</html>

列表模板示例:

<!-- templates/record_list.html -->
<!DOCTYPE html>
<html>
<head>
    <title>记录列表</title>
</head>
<body>
    <h1>记录列表</h1>
    <a href="{% url 'record_create' %}">添加新记录</a>
    <ul>
        {% for record in records %}
            <li>
                {{ record.product_name.name }} - {{ record.country.name }}/{{ record.state.name }} - {{ record.status }} - {{ record.datetime|date:"m-d-Y H:i:s" }}
                <a href="{% url 'record_update' record.pk %}">编辑</a>
                <a href="{% url 'record_delete' record.pk %}">删除</a>
            </li>
        {% endfor %}
    </ul>
</body>
</html>

删除确认模板:

<!-- templates/record_confirm_delete.html -->
<!DOCTYPE html>
<html>
<head>
    <title>删除记录</title>
</head>
<body>
    <h1>删除记录</h1>
    <p>确定要删除 "{{ record }}" 吗?</p>
    <form method="post">
        {% csrf_token %}
        <button type="submit">确认删除</button>
        <a href="{% url 'record_list' %}">取消</a>
    </form>
</body>
</html>

六、初始化基础数据

通过Django Shell添加初始的国家、州、产品类型及产品名数据:

# 运行命令进入shell:python manage.py shell
from myapp.models import Country, State, ProductType, ProductName

# 添加国家和州
usa = Country.objects.create(name='USA')
State.objects.create(country=usa, name='California')
State.objects.create(country=usa, name='New York')

china = Country.objects.create(name='中国')
State.objects.create(country=china, name='北京')
State.objects.create(country=china, name='上海')

# 添加产品类型和产品名
vegetable = ProductType.objects.create(name='蔬菜')
ProductName.objects.create(product_type=vegetable, name='卷心菜')
ProductName.objects.create(product_type=vegetable, name='土豆')

fruit = ProductType.objects.create(name='水果')
ProductName.objects.create(product_type=fruit, name='苹果')
ProductName.objects.create(product_type=fruit, name='橙子')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:16:16