我正在尝试在CharField上为模型执行自然排序(这里是简化版本(:
class House(models.Model):
number = models.CharField(max_length=32)
def __str__(self):
return str(self.number)
>>> House.objects.all()
<QuerySet [<House: 2>, <House: 1>, <House: 4>, <House: 3>, <House: 1b>, <House: 2b>, <House: 1c>, <House: 13c>, <House: 10>, <House: 2e>, <House: 3ab>]>
我已经设法通过原始SQL查询对其进行了排序:
House.objects.raw("SELECT * FROM entry_house ORDER BY(substring(number, '^[0-9]+'))::int, substring(number, '[0-9].*$')")
但是我需要获取QuerySet对象而不是RawQuerySet(对于我们当前的分页实现(。由于数据量巨大,因此无法循环访问所有原始查询集。
如何将 RawQuerySet 的结果转换为 QuerySet 甚至更好,如何将此原始 SQL 查询转换为 Django QuerySet API?
使用 postgres 后端,您可以使用 regexp_replace
函数执行以下操作:
from django.db.models import Func, F, Value, IntegerField
from django.db.models.functions import Cast
House.objects.all()
.annotate(inumber=Cast(
Func(F('number'), # take number
Value('[^d]'), # pattern to replace: non-digits
Value(''), # replacement
Value('g'), # global flag; replace all occurrences
function='regexp_replace'),
IntegerField())) # output type of cast
.order_by('inumber', 'number') # fallback to non-digit portion
该Func
从number
中删除非数字(Django 数据库函数(。批注将结果强制转换为整数。可能有更好的功能可用,但对于上述数据,这应该有效。