Django如何在Admin过滤器中展示外键关联的用户全名?
错误原因
list_filter仅支持接收模型原生字段、跨关联关系的字段,无法直接识别Admin类中定义的自定义属性,你编写的assignee_full_name是Admin类的自定义方法,Django Admin的筛选逻辑无法将其映射为数据库查询条件,因此抛出E116错误。
解决方案:自定义筛选器
通过继承admin.SimpleListFilter实现自定义筛选逻辑,即可在筛选下拉框展示用户全名,同时保证筛选功能正常:
步骤1:定义自定义筛选器类
在Admin所在文件中添加以下代码:
from django.contrib import admin from django.utils.translation import gettext_lazy as _ class AssigneeFullNameFilter(admin.SimpleListFilter): # 筛选器在页面上显示的标题 title = _('经办人全名') # URL参数中使用的参数名 parameter_name = 'assignee_id' def lookups(self, request, model_admin): # 构造下拉选项:格式为(参数值, 页面显示文本) # 这里仅返回当前模型实际关联的用户,避免出现无用选项 used_users = model_admin.model.objects.select_related('assignee').values_list('assignee__id', 'assignee__first_name', 'assignee__last_name').distinct() return [ (user_id, f"{first_name}{last_name}") for user_id, first_name, last_name in used_users if user_id is not None ] def queryset(self, request, queryset): # 选中选项时的过滤逻辑 if selected_user_id := self.value(): return queryset.filter(assignee_id=selected_user_id) return queryset
步骤2:替换Admin配置中的筛选字段
修改你的ClientAdmin配置:
class ClientAdmin(admin.ModelAdmin): # 把原来的assignee_full_name替换为自定义筛选器类 list_filter = ('status', AssigneeFullNameFilter) # 如果你需要在列表页也展示全名,可以保留该方法,同时加入list_display list_display = ('status', 'assignee_full_name') def assignee_full_name(self, obj): if not obj.assignee: return "-" return f"{obj.assignee.first_name}{obj.assignee.last_name}" # 可选配置:支持点击列头按全名排序 assignee_full_name.admin_order_field = ('assignee__first_name', 'assignee__last_name')
可选调整
如果需要筛选下拉框展示所有系统用户,而非仅关联了当前模型的用户,可以把lookups方法的逻辑替换为直接遍历User表:
def lookups(self, request, model_admin): from django.contrib.auth.models import User return [ (user.id, f"{user.first_name}{user.last_name}") for user in User.objects.all() ]
内容的提问来源于stack exchange,提问作者David Rhoden
相关产品推荐
相关产品推荐

