Django - order_by () char и numeric - PullRequest
       20

Django - order_by () char и numeric

0 голосов
/ 20 февраля 2019

Мне нужно отсортировать список объектов, содержащих имена хостов.

Имена хостов имеют следующие форматы: h1, h5, h10, h12, h12-abc, h1000, x10

Если я использую order_by ('hostname'), он будет выглядеть следующим образом:

h1, h10, h1000, h12, h12-abc, h5, x10

Как бы я достиг такого порядка:

h1, h5, h10, h12, h12-abc, h1000, x10

Имена хостов всегда начинаются с символа, затем 1-4 цифры и частично расширения, как, например, '-abc '.

Полагаю, мне нужно использовать Substr (), чтобы извлечь число и как-то упорядочить числа, чтобы «10» не было в списке до «5».

Споиск Я нашел несколько старых примеров с помощью extra (), но в документации Django сказано, что в будущем он будет устаревшим, и «используйте этот метод как последнее средство» https://docs.djangoproject.com/en/2.1/ref/models/querysets/#extra

Что такое способ сделать это на будущее

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Я получил его для работы с дополнительным полем normalized_hostname, которое также не зависит от базы данных.Реализовано в модели с помощью Django Signals pre_save()

https://docs.djangoproject.com/en/2.1/ref/signals/#pre-save

Приведенный ниже код преобразует имя хоста в формат, который затем можно использовать с order_by('normalized_hostname')

Примеры:
hostname -> normalized_hostname

h1 -> h0001 
h5 -> h0005, 
h10 -> h0010 
h12 -> h0012
h12-abc -> h0012-abc 
h1000 -> h1000 
x10 -> x0010

models.py

from django.db.models.signals import pre_save
import re

class MyModel(models.Model):
  the solution is also database independent  hostname = models.CharField(max_length=64)
    normalized_hostname = models.CharField(max_length=64)



def create_normalize_hostname(instance):
    normalize = re.sub("\D", "", instance.hostname).zfill(4)
    normalized_hostname = re.sub("(\d{1,4})", normalize, instance.hostname)
    return normalized_hostname

def receiver(sender, instance, *args, **kwargs)
    instance.normalized_hostname = create_normalize_hostname(instance)

pre_save.connect(receiver, sender=ModelName)

Теперь он будет выглядеть какэто:

h1, h5, h10, h12, h12-abc, h1000, x10
0 голосов
/ 20 февраля 2019

вы можете использовать f-выражения

from django.db.models import F, Value, TextField, IntegerField
from django.contrib.postgres.fields import ArrayField
from django.db.models.expressions import Func

sql = ordModel.objects.annotate(
        num=Cast(
            Func(
                F('hostname'),
                Value("\d+"),
                function='regexp_matches',
            ),
            output_field=ArrayField(IntegerField())
        ),
        char=Func(
            F('hostname'),
            Value("\D+"),
            function='regexp_matches',
            output_field=ArrayField(TextField())
        )
    ).order_by('char', 'num', ).values('hostname')

Мой результат для того же списка значений:

<QuerySet [
{'hostname': 'h1'},
{'hostname': 'h5'},
{'hostname': 'h10'},
{'hostname': 'h12'},
{'hostname': 'h12-abc'},
{'hostname': 'h1000'},
{'hostname': 'x10'}]>

о функции базы данных, которую вы можетеreadL regexp_match

...