Django将原始SQL排序转换为QuerySet API

时间:2018-01-22 08:43:10

标签: python sql django postgresql

我试图在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?

1 个答案:

答案 0 :(得分:2)

使用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

FuncnumberDjango database functions)中移除非数字。注释将结果转换为整数。可能有更好的功能,但对于上述数据,这应该可行。