Python 'length'和'name'排序参数不符合我的要求
我有一个Python 'length'和'name'排序参数不符合我的要求,python,django,django-rest-framework,Python,Django,Django Rest Framework,我有一个PhysicalServer型号: class PhysicalServer(models.Model): name = models.CharField(max_length=32) cabinet = models.ForeignKey(to=Cabinet, on_delete=models.DO_NOTHING, related_name="physical_servers") physical_server_model = models.ForeignK
PhysicalServer
型号:
class PhysicalServer(models.Model):
name = models.CharField(max_length=32)
cabinet = models.ForeignKey(to=Cabinet, on_delete=models.DO_NOTHING, related_name="physical_servers")
physical_server_model = models.ForeignKey(to=PhysicalServerModel, null=True, on_delete=models.DO_NOTHING)
...
class Meta:
ordering = ['-cabinet', '-physical_server_model', 'name']
其列表API视图如下所示:
class PhysicalServerListAPIView(ListAPIView):
serializer_class = PhysicalServerListSerializer
permission_classes = [AllowAny]
pagination_class = CommonPagination
def get_queryset(self):
qs = PhysicalServer.objects.filter(**filters)
return qs.annotate(length=Length('name')).order_by('length', 'name') # there if I put the `name` first(order_by('name', 'length')), also inconformity my requirement.
我的physicalserver实例名称如下所示:
我的问题是,当我将此用于列表排序时:
return qs.annotate(length=Length('name')).order_by('length', 'name')
结果将是:
SE01-A1
SE01-A2
SE01-A3
...
SE01-A9
SE01-C1
SE01-C2
SE01-C3
...
SE01-A10
SE01-A11
SE01-A12
...
SE01-A1
SE01-A11
SE01-A12
SE01-A13
...
SE01-A2
SE01-A21
...
SE01-A3
...
如果我使用以下选项进行排序:
return qs.annotate(length=Length('name')).order_by('name', 'length')
结果将是:
SE01-A1
SE01-A2
SE01-A3
...
SE01-A9
SE01-C1
SE01-C2
SE01-C3
...
SE01-A10
SE01-A11
SE01-A12
...
SE01-A1
SE01-A11
SE01-A12
SE01-A13
...
SE01-A2
SE01-A21
...
SE01-A3
...
我怎样才能这样分类:
SE01-A1
SE01-A2
SE01-A3
SE01-A4
...
SE01-A10
...
SE01-C1
SE01-C2
...
?用于将名称的第一部分与末尾的数字分开,然后首先按此新注释排序
from django.db.models.functions import Substr, Length
qs = qs.annotate(letters=Substr('name', 1, 6), length=Length('name'))
qs = qs.order_by('letters', 'length', 'name')
return qs
您需要从字符串中提取数字。Postgres和mysql提供了
regexp\u replace
功能(我不确定其他数据库)。但是Django没有提供实现,因此我们将编写自己的:
我假设您希望将名称拆分为末尾的数字,然后使用前半部分进行排序,最后是数字。(这对您来说很好,直到您开始获得连字符前面的3位数字,即SE99-A1、SE100-A1)
这可能适用于我的情况,但在我的情况下,
名称几乎是固定的,因此,是否有更好的方法来实现这一点?例如,如果长度不是固定的,则不能对substr使用1,6
。您可以根据需要多次重复此策略,迭代name
的可能性,但在某些情况下,必须将字段固定为特定格式,以便任何类型的排序都能正常工作。另一种方法是将字段拆分为多个字段,其中包含构成名称的基本组件(这是我的建议),或者考虑编写一些数据库函数——当然,格式越复杂,运行查询所需的时间就越长。您正在寻找所谓的“自然排序”。请参见类似问题:,,在第二个代码段中,它不应该是RegexpReplace
而不是RegexpReplace2
?