2016-12-16 62 views
0

我想通过charfield中的数字来定购QuerySet。 我有这样的代码:如何在包含数字的charfield中在Django中订购QuerySet?

MyTable.objects.all().order_by('my_char_field') 

有 “my_char_field” 的一些例子:

"ver3", "ver10", "x5.1 (1)", "ver4", "x5.1 (2)" 

与上面的代码顺序的结果是:

"ver10", "ver3", "ver4", "x5.1 (1)", "x5.1 (2)" 

但订单我想要的是:

"ver3", "ver4", "ver10", "x5.1 (1)", "x5.1 (2)" 

如何获得自然顺序?

+1

是否总是与'ver'开始? – AKS

+0

这些是唯一的变化吗?这个char字段是否总是以一系列数字结尾并以字母序列开头?该版本内部是否有点'ver 2.1.2'? – AKS

+0

@AKS版本内部可能有一个点,不同的开始和结束 – MouTio

回答

5

它似乎更像是一个数据存储问题。如果你改变你的数据结构

version_type = models.CharField() 
version_num = models.FloatField() 
version_revision = models.SmallIntegerField(null=True) 

unique_together = [('version_type', 'version_num', 'version_revision')] 

.order_by('version_type', 'version_num', 'version_revision') 

这也将解决您的下一个问题就变得容易“我怎样才能最有效地获得式‘版本’的所有版本?”

+1

是的,这是要走的路。 – e4c5

2

尽管可以在客户端获取并进行排序,但您也可以使用Substr函数在服务器端执行此操作。

from django.db.models.functions import Substr 

MyTable.objects.all().order_by(Substr('my_char_field',3)) 

更新:

我工作的另一个更新的答案,当问题被再次更新!以下是不完整的,但你可以建立它。

MyTable.objects.annotate(
    sort_field=Case(
     When(my_char_field__start_with='ver', Then=Substr(my_char_field,3), 
     When(my_char_field__start_with='x', Then=Substr(my_char_field,1), 
     default = my_char_field) 

).order_by('sort_field) 

您还需要使用Cast函数来将sort_field强制转换为int。这将是一个长期的查询!

+0

我相信你没有看过更新的帖子?而且,这对于'10'不适用,因为它是字符串。 – AKS

+0

我在没有看到更新的情况下编写了这个答案。猜猜我将不得不添加更新。 – e4c5

+1

@Sayse对这个问题进行了太多修改,但是新的更新应该会在轨道上得到OP – e4c5

0

就像@AKS提到的那样,在内存中进行排序可能效率低下。只要你有一个大表,你想只拉第一页结果排序。然后,您必须从数据库中提取每一行,然后才能进行排序。


也许你可以尝试在添加新记录时添加另一个从“排序”字段填充的字段。这一次,你可以为你做数据库排序工作。

Something From Vem3456 to Vem6543