如何使用字段子串为Django QuerySet添加注解?
从字段子串生成Django QuerySet注解的实现方法
你提供的代码思路没问题,但存在一个关键错误:Django的F对象并没有Index()方法,直接调用会报错。要实现从email字段提取域名并添加注解,需要借助Django内置的数据库函数来定位字符位置,以下是正确的实现方式:
通用数据库兼容方案
先导入所需的函数:
from django.db.models import Count, F from django.db.models.functions import Substr, StrIndex
然后构建QuerySet:
query_by_domain = ( queryset # 标注@符号在email中的位置 .annotate(at_position=StrIndex(F('email'), '@')) # 从@的下一位开始截取,得到域名 .annotate(domain=Substr(F('email'), F('at_position') + 1)) # 过滤掉无@的无效邮箱(可选) .filter(at_position__gt=0) # 按域名分组 .values('domain') # 统计每组记录数 .annotate(count=Count('id')) # 按域名排序 .order_by('domain') )
PostgreSQL专属简化方案
如果你的项目基于PostgreSQL数据库,可以用SplitPart函数直接分割字符串,代码更简洁:
from django.db.models import Count, F from django.db.models.functions import SplitPart query_by_domain = ( queryset # 按@分割email,取第2部分作为域名 .annotate(domain=SplitPart(F('email'), '@', 2)) .filter(domain__ne='') .values('domain') .annotate(count=Count('id')) .order_by('domain') )
关键说明
StrIndex返回指定字符在字符串中的位置(从1开始计数),找不到则返回0,因此可以通过filter(at_position__gt=0)过滤格式无效的邮箱。Substr的参数为:源字段、起始位置、截取长度(可选,不填则截取到字符串末尾)。SplitPart的参数为:源字段、分隔符、要提取的分割部分序号(从1开始计数)。
内容的提问来源于stack exchange,提问作者Ajax
相关产品推荐
相关产品推荐

