Django 3.0 Admin多层级分类模型字段搜索实现疑问
实现Django Admin多层级分类字段搜索
当然可以实现多层级分类的搜索功能,下面分场景给出具体实现方案:
前提假设
先假设你的分类模型结构如下(如果你的模型字段不同,只需对应调整字段名即可):
# models.py from django.db import models class Category(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children') def __str__(self): return self.name
场景1:在分类列表页面搜索下属所有层级子分类的字段
现有代码的search_fields仅支持当前模型字段,要搜索多层级子分类,需要重写get_search_results方法,结合Django的关联查询(双下划线__)和Q对象实现递归搜索:
修改你的注册函数如下:
from django.contrib import admin from django.db.models import Q from .models import * def register_models(models_list): for model, fields in models_list.items(): # 筛选当前模型的本地字段 model_fields = tuple(field.name for field in model._meta.fields if field.name in fields) # 提取需要关联搜索的子模型字段(比如children__name) related_fields = [f for f in fields if '__' in f] class Admin(admin.ModelAdmin): list_display = ('__str__', *model_fields) list_filter = model_fields search_fields = list(model_fields) # 基础搜索自身字段 def get_search_results(self, request, queryset, search_term): queryset, use_distinct = super().get_search_results(request, queryset, search_term) if not search_term: return queryset, use_distinct # 构建搜索条件:自身字段 + 所有层级子分类字段 search_q = Q() # 搜索当前模型字段 for field in model_fields: search_q |= Q(**{f"{field}__icontains": search_term}) # 递归构建子分类的搜索条件,限制层级避免性能问题 def build_child_query(related_name, max_depth=5): child_q = Q() if max_depth <= 0: return child_q # 匹配当前层级的关联字段 for rel_field in related_fields: if rel_field.startswith(f"{related_name}__"): child_field = rel_field.split(f"{related_name}__", 1)[1] child_q |= Q(**{f"{rel_field}__icontains": search_term}) # 递归处理下一级子分类 child_q |= build_child_query(f"{related_name}__children", max_depth - 1) return child_q # 添加子分类的搜索条件(假设子分类关联名是children) search_q |= build_child_query('children') queryset |= model.objects.filter(search_q) return queryset, use_distinct admin.site.register(model, Admin)
使用方式
在注册模型时,传入包含关联子分类字段的配置:
models_list = { Category: ['name', 'description', 'children__name', 'children__description'] } register_models(models_list)
这样在分类列表页面搜索test时,会匹配:
- 自身名称/描述含
test的分类 - 任意层级子分类的名称/描述含
test的父分类
场景2:在分类编辑页面搜索下属子分类
如果需要在某个分类的编辑页面(比如category2的详情页),对其下属子分类列表进行搜索,可以通过内联模型实现:
在注册函数中添加内联类:
def register_models(models_list): for model, fields in models_list.items(): # ... 保留之前的model_fields和related_fields逻辑 # 定义子分类内联类 class CategoryInline(admin.TabularInline): model = model fk_name = 'parent' search_fields = [f.split('__')[-1] for f in related_fields if f.startswith('children__')] extra = 0 class Admin(admin.ModelAdmin): list_display = ('__str__', *model_fields) list_filter = model_fields search_fields = list(model_fields) inlines = [CategoryInline] # 添加内联 # ... 保留get_search_results方法(如果需要场景1的功能) admin.site.register(model, Admin)
这样在编辑category2时,页面下方的子分类列表会出现搜索框,可直接搜索子分类的字段内容。
关键说明
- Django的双下划线
__用于跨模型关联查询,children__name表示子分类的name字段,children__children__name表示孙子分类的name字段。 - 设置
max_depth参数是为了避免无限递归,防止数据库性能问题,可根据实际层级调整。 - 内联模型的
search_fields仅作用于当前内联的子分类列表,适合单层级子分类的快速搜索。
内容的提问来源于stack exchange,提问作者vladimir
相关产品推荐
相关产品推荐

