自定义Django Transform实现字符串转Int/Null时遇AttributeError求助
解决Django自定义
as_int Transform的AttributeError问题 错误根源是你在When条件中误用了Regex(这是查询用的Lookup类,而非表达式函数),传入self.lhs(Col对象)时触发了字符串分割逻辑的错误。以下是修正后的代码:
from django.db.models import Case, Cast, Value, When from django.db.models.functions import RegexpMatches from django.db.models.lookups import Transform from django.db import models class AsIntTransform(Transform): lookup_name = "as_int" output_field = models.IntegerField() def as_sql(self, compiler, connection): # 使用RegexpMatches函数执行正则匹配(Django 3.2+支持) case_expr = Case( When( RegexpMatches(self.lhs, r"^\d+$"), then=Cast(self.lhs, models.IntegerField()), ), default=Value(None), output_field=models.IntegerField(), ) sql, params = case_expr.as_sql(compiler, connection) return sql, params models.CharField.register_lookup(AsIntTransform) models.TextField.register_lookup(AsIntTransform)
核心修改说明:
- 替换
Regex为RegexpMatches:Regex是用于查询的Lookup类(如field__regex=r'...'),而RegexpMatches是数据库函数表达式,能正确处理self.lhs(Col对象)。 - 给
Case指定output_field:明确输出类型,避免潜在的类型推断异常。
若你的Django版本低于3.2,可手动用Func构建数据库特定的正则匹配逻辑:
# 以MySQL为例(PostgreSQL需将function改为'~') from django.db.models import Func # 替换原RegexpMatches行: Func(self.lhs, Value(r"^\d+$"), function='REGEXP')
测试你的查询逻辑:
Comment.objects.filter(body__as_int__gt=5)
此时body为"37"的记录会被转为整数37参与比较,非纯数字内容会被视为NULL,不会被纳入结果(NULL与任何值比较均返回NULL,不满足gt=5的条件)。
内容的提问来源于stack exchange,提问作者Daniel Gordos
相关产品推荐
相关产品推荐

