Django技术问题:如何获取多对多字段中已选选项的列表?
解决Django中无法获取已选员工列表的AttributeError问题
问题场景
登录的管理员(Gestor)选择员工(Funcionarios)后,需要查看已选员工的列表,但在尝试获取数据时报错。
现有代码
models.py
class Equipe(models.Model): gestor = models.ForeignKey(Gestor, on_delete=models.PROTECT, default="") funcionario = models.ManyToManyField(User) def __str__(self): return self.nome def get_funcionario(self): return "\n".join([p.funcionario for p in self.funcionario.all()])
views.py
def listaFuncionario(request): gest = Gestor.objects.get(user_id = request.user.id) equipe = Equipe.objects.filter(gestor_id = gest) equipes = gest.equipe_set.all() func = equipes.funcionario.all() context = {'func':func} return render(request, 'listaFunc.html', context)
报错信息
func = equipes.funcionario.all() AttributeError: 'QuerySet' object has no attribute 'funcionario' [02/Nov/2022 15:15:06] "GET /funcionarios HTTP/1.1" 500 65882
错误原因
gest.equipe_set.all()返回的是QuerySet对象(即当前管理员关联的所有Equipe实例的集合),而funcionario是单个Equipe模型的多对多字段,只能在单个Equipe实例上调用,不能直接在QuerySet集合上访问这个属性,因此触发AttributeError。
解决方案
提供两种常用修正方式,可根据需求选择:
方式1:遍历收集所有关联员工并去重
遍历管理员的所有Equipe,收集每个Equipe下的员工,最后去重避免重复数据:
def listaFuncionario(request): gest = Gestor.objects.get(user_id=request.user.id) # 预加载关联数据,减少数据库查询次数 equipes = gest.equipe_set.prefetch_related('funcionario').all() func_set = set() for equipe in equipes: func_set.update(equipe.funcionario.all()) context = {'func': func_set} return render(request, 'listaFunc.html', context)
方式2:直接跨表查询获取所有关联员工
利用Django的反向关联特性,直接查询当前管理员所有Equipe关联的User对象:
def listaFuncionario(request): gest = Gestor.objects.get(user_id=request.user.id) # 跨表查询并去重,避免同一员工重复出现 func = User.objects.filter(equipe__gestor=gest).distinct() context = {'func': func} return render(request, 'listaFunc.html', context)
额外优化说明
- 两种方式中的去重操作(
set()或distinct())用于避免同一员工被多个Equipe关联时出现重复数据。 - 方式1中使用
prefetch_related('funcionario')可减少数据库查询次数,避免N+1查询问题,提升性能。 - 原models中的
get_funcionario方法存在错误:p.funcionario应改为p.username或p.get_full_name()(因为p是User实例,无funcionario属性),修正后代码:
def get_funcionario(self): return "\n".join([p.username for p in self.funcionario.all()])
内容的提问来源于stack exchange,提问作者Gabriel Batista dos Santos
相关产品推荐
相关产品推荐

