You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中通过关联模型直接按desig_name过滤组内用户?

解决Django按关联模型字段过滤查询集的问题

你完全可以不用循环筛选再用user_id__in,直接利用Django的关联模型双下划线查询特性,就能像过滤contact_no、user_name一样直接通过**user_filter实现职称名称的过滤,而且性能会更好(因为过滤逻辑在数据库层面完成,不用加载额外数据到内存)。

核心思路

Django ORM支持通过双下划线(__)跨关联模型查询字段。你的User模型通过desigs关联到Designation,再通过desig_type关联到DesigType,所以可以直接用desigs__desig_type__desig_name作为查询字段。

具体实现步骤

  1. 修正模型中的小错误
    先提个小细节:你的模型类继承的是models.model,应该改成首字母大写的models.Model,否则会报错;另外max_length参数需要传整数,不是字符串,顺手一起修正:

    class Group(models.Model):
        group_id = models.CharField(max_length=10)
        name = models.CharField(max_length=20)
    
    class User(models.Model):
        user_id = models.CharField(max_length=10)
        grp = models.ForeignKey(Group, null=True, blank=True, on_delete=models.SET_NULL)  # 建议补充on_delete参数
        user_name = models.CharField(max_length=50)
        contact_no = models.CharField(max_length=20)
    
    class DesigType(models.Model):
        desig_name = models.CharField(max_length=10)
    
    class Designation(models.Model):
        user = models.ForeignKey(User, null=True, blank=True, related_name='desigs', on_delete=models.SET_NULL)
        desig_type = models.ForeignKey(DesigType, null=True, blank=True, related_name='desigs', on_delete=models.SET_NULL)
    
  2. 构造支持职称过滤的user_filter
    当UI传入搜索文本时,你只需要把过滤键设为desigs__desig_type__desig_name__icontains(模糊匹配)或者desigs__desig_type__desig_name__exact(精确匹配),值为用户输入的文本,然后直接传入filter(**user_filter)即可。

    比如视图中的代码可以改成这样:

    def your_view(request, grp_id):
        group = Group.objects.get(pk=grp_id)
        search_text = request.GET.get('search_text', '')
        
        # 构造user_filter
        user_filter = {}
        # 按职称名称模糊匹配(如果是精确匹配就换成__exact)
        if search_text:
            user_filter['desigs__desig_type__desig_name__icontains'] = search_text
        # 保留原有其他字段的过滤逻辑,比如用户名、手机号
        # contact_search = request.GET.get('contact_search', '')
        # if contact_search:
        #     user_filter['contact_no__icontains'] = contact_search
        
        # 执行查询,用distinct()避免同一个用户因多个职称被重复返回
        _queryset = group.user_set.filter(**user_filter).distinct()
        
        # 后续处理返回结果...
    
  3. 为什么不需要cached_property?
    你之前用cached_property生成的desig_types是用户实例的属性,只能在单个用户实例上判断是否包含某个职称,但无法直接用于QuerySet的过滤。而用ORM的关联查询是直接在数据库层面筛选符合条件的用户,效率更高,代码更简洁。

补充说明

  • 如果你的搜索是“或”逻辑(比如用户名包含搜索文本或职称包含搜索文本),那需要用Q对象来组合条件:
    from django.db.models import Q
    
    user_filter = Q(user_name__icontains=search_text) | Q(desigs__desig_type__desig_name__icontains=search_text)
    _queryset = group.user_set.filter(user_filter).distinct()
    
  • 加上distinct()很重要,因为一个用户可能有多个职称,查询时会返回多条重复的用户记录,distinct()可以帮你去重。

内容的提问来源于stack exchange,提问作者Sidharth Samant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:02:24