在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
相关产品推荐
相关产品推荐

