Django - 按CharField值长度过滤查询集

16 投票
2 回答
10098 浏览
提问于 2025-04-18 04:39

我有一个旧的模型,里面有一个叫做 CharField 的字段,或者是基于 CharField 的字段,像这样:

class MyModel(models.Model):
    name = models.CharField(max_length=1024, ...)
    ...

我需要进行数据迁移,把这个字段的最大长度设置为255个字符。首先,我要写一个 datamigration,让所有超过255个字符的值适应接下来的 schemamigration,这样才能修复这个字段的最大长度,等这个步骤完成后我会继续进行。

问题是,我的数据量非常非常大,而且我知道并不是所有的行都包含超过255个字符的 MyModel.name,我只想在迁移时考虑那些确实超过的行。

有没有办法通过django的ORM来筛选出符合这个条件的对象呢?比如说:

MyModel.objects.filter(name__len__gte=255)

这样做会很好,但我觉得这可能不太可能,或者至少没有那么简单。

有没有人知道怎么实现这个查询呢?

谢谢!

2 个回答

7

如果你发现自己在使用很多额外的东西和正则表达式,按照@BBT的建议,我接着实现了如下的转换:

# utils.db

from django.db.models import Transform
from django.db.models import CharField

class CharacterLength(Transform):
    lookup_name = 'len'
    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return "LENGTH(%s)" % lhs, params

CharField.register_lookup(CharacterLength)

之后,我可以对“mycolname”进行级联查找,方法如下:

from utils.db import *

queryset.filter(mycolname__len__gte=10)
28

最近的 Django 版本里有一个内置的功能叫做 django.db.models.functions.Length,这样你就可以直接使用它来计算字符串的长度:

MyModel.objects.annotate(length=Length('text')).filter(length__gt=254)

你可以查看这个链接了解更多信息:https://docs.djangoproject.com/en/1.11/ref/models/database-functions/#length

旧的回答:

我觉得你有两个选择:

第一种是使用查询集中的 'extra' 功能:

MyModel.objects.extra(where=["CHAR_LENGTH(text) > 254"])

第二种是使用正则表达式查找,不过我想这样会比较慢:

MyModel.objects.filter(text__regex = r'^.{254}.*')

撰写回答