如何在Django Admin中基于分类下拉框过滤类型下拉选项?
实现Django Admin中Category与ItemType的联动下拉过滤
先修复模型定义问题
Plant模型的name字段缺少必填参数,先补充完整:
class Plant(models.Model): category = models.ForeignKey(Category , on_delete=models.SET_NULL , null=True) type = models.ForeignKey(ItemType, on_delete=models.SET_NULL,null = True) name = models.CharField(max_length=200) # 添加max_length参数
步骤1:编写获取ItemType的后端视图
在你的app目录下的views.py中添加以下视图,用于根据分类ID返回对应的类型数据:
from django.http import JsonResponse from .models import ItemType def get_item_types(request): category_id = request.GET.get('category_id') # 过滤出指定分类下的ItemType,只返回id和name字段 item_types = ItemType.objects.filter(category_id=category_id).values('id', 'name') return JsonResponse(list(item_types), safe=False)
步骤2:配置路由
在app目录下的urls.py中添加视图路由:
from django.urls import path from . import views urlpatterns = [ # 其他已有路由... path('get-item-types/', views.get_item_types, name='get_item_types'), ]
确保项目根目录的urls.py已经包含该app的路由(比如path('your-app-name/', include('your_app.urls')))。
步骤3:自定义Admin表单与媒体资源
在app目录下的admin.py中,自定义Plant的管理表单,并引入JS实现联动:
from django import forms from django.contrib import admin from .models import Category, ItemType, Plant # 自定义Plant管理表单 class PlantAdminForm(forms.ModelForm): class Meta: model = Plant fields = '__all__' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 初始化时,如果已有选中的分类,过滤对应的类型选项 if self.instance.category: self.fields['type'].queryset = ItemType.objects.filter(category=self.instance.category) else: self.fields['type'].queryset = ItemType.objects.none() # 配置Plant的Admin类 class PlantAdmin(admin.ModelAdmin): form = PlantAdminForm # 引入自定义JS文件 class Media: js = ('admin/js/plant_admin.js',) # 注册模型 admin.site.register(Category) admin.site.register(ItemType) admin.site.register(Plant, PlantAdmin)
步骤4:编写JS联动逻辑
在项目的static/admin/js/目录下创建plant_admin.js文件(若目录不存在则手动创建),写入以下代码:
document.addEventListener('DOMContentLoaded', function() { const categorySelect = document.getElementById('id_category'); const typeSelect = document.getElementById('id_type'); // 监听分类下拉框的变化事件 categorySelect.addEventListener('change', function() { const categoryId = this.value; // 清空类型下拉框 typeSelect.innerHTML = '<option value="">---------</option>'; if (categoryId) { // 发送请求获取对应分类的类型数据 fetch(`/your-app-name/get-item-types/?category_id=${categoryId}`) .then(response => response.json()) .then(data => { data.forEach(itemType => { const option = document.createElement('option'); option.value = itemType.id; option.textContent = itemType.name; typeSelect.appendChild(option); }); }) .catch(error => console.error('加载类型数据失败:', error)); } }); });
注意将/your-app-name/替换为你实际的app路由前缀(比如app名为plants则写/plants/)。
额外注意事项
- 确保项目
settings.py中已正确配置STATIC_URL和STATICFILES_DIRS,静态文件能被正常加载; - 生产环境下需要执行
python manage.py collectstatic收集静态文件; - 测试时若JS未生效,可尝试清除浏览器缓存。
内容的提问来源于stack exchange,提问作者Ahmed Morad
相关产品推荐
相关产品推荐

