如何在Django Admin多对多自动字段中获取选中项实现树形分类搜索
实现Django Admin中Movie分类的树形层级搜索
1. 修改Genre Admin的查询过滤逻辑
在admin.py的AdminGenre类中,重写get_queryset方法,根据请求参数过滤出指定父分类的所有后代节点:
from mptt.admin import DraggableMPTTAdmin from django.contrib import admin from .models import Genre, Movie @admin.register(Genre) class AdminGenre(DraggableMPTTAdmin): list_display = ["tree_actions", "indented_title"] list_display_links = ["indented_title"] search_fields = ["name__istartswith"] def get_queryset(self, request): qs = super().get_queryset(request) # 获取请求中的父分类ID参数 parent_id = request.GET.get('parent_id') if parent_id: try: parent_genre = Genre.objects.get(id=parent_id) # 获取该父分类的所有后代节点(不包含父分类本身) qs = parent_genre.get_descendants(include_self=False) except Genre.DoesNotExist: qs = qs.none() return qs @admin.register(Movie) class AdminMovie(admin.ModelAdmin): autocomplete_fields = ["genre"] class Media: # 引入自定义JS文件实现前端交互 js = ('admin/js/genre_autocomplete.js',)
2. 添加前端父分类选择与请求参数传递
在项目的static/admin/js目录下创建genre_autocomplete.js文件,实现父分类选择器并修改自动完成请求的参数:
document.addEventListener('DOMContentLoaded', function() { const genreSelect = document.getElementById('id_genre'); if (!genreSelect) return; // 创建父分类选择下拉框 const parentSelector = document.createElement('select'); parentSelector.id = 'parent_genre_selector'; parentSelector.className = 'vTextField'; parentSelector.style.marginRight = '10px'; // 添加默认选项 const defaultOption = document.createElement('option'); defaultOption.value = ''; defaultOption.textContent = '选择父分类(可选)'; parentSelector.appendChild(defaultOption); // 加载所有顶级分类(无父分类的节点) fetch('/admin/你的应用名/genre/?format=json') // 替换为你的实际应用名称 .then(resp => resp.json()) .then(data => { data.forEach(item => { if (!item.parent) { const option = document.createElement('option'); option.value = item.id; option.textContent = item.name; parentSelector.appendChild(option); } }); }); // 将选择器插入到分类选择框前 genreSelect.parentNode.insertBefore(parentSelector, genreSelect); // 修改Select2的AJAX请求,携带父分类ID参数 $(genreSelect).on('select2:open', function() { const select2 = $(this).data('select2'); const originalAjax = select2.options.get('ajax'); select2.options.set('ajax', { url: originalAjax.url, data: function(params) { return { term: params.term || '', parent_id: parentSelector.value || '' }; }, processResults: originalAjax.processResults, cache: originalAjax.cache }); }); });
3. 功能效果
- 在Movie的创建/编辑页面,会新增一个“选择父分类”下拉框,默认展示所有顶级分类。
- 选择某父分类后,点击Genre的自动完成输入框,搜索结果将仅包含该父分类下的所有子节点(含孙子节点等后代)。
- 不选择父分类时,搜索逻辑保持原有状态,返回所有分类。
内容的提问来源于stack exchange,提问作者S F
相关产品推荐
相关产品推荐

