Упорядочить Django Queryset по атрибуту, который может быть char или int?

У меня есть следующая модель, которую мне нужно упорядочить по атрибуту grade, но этот атрибут может быть либо символом, либо целым числом (K, KA, KF, NA, 1, 2, 3 и т.д.)... какой лучший способ достичь этого? Мы используем MS SQL в качестве бэкенда (я не могу использовать __regex, потому что версия БД не поддерживает его).

Я добавил атрибут first_letter_group к набору запросов, потому что любая оценка с несколькими буквами должна рассматриваться как первая буква (KA = K, KN = K и т.д.)

Я пытаюсь упорядочить эти результаты сначала по алфавиту, затем по возрастанию (например, "P, K, 1, 2, 3, 4...")

# This is an unmanaged model
class Enrollment(models.Model):
    id = models.IntegerField(db_column="ID", primary_key=True)
    location_id = models.IntegerField(db_column="loc_id")
    grade = models.CharField(db_column="grade", max_length=10)
    end_year = models.IntegerField(db_column="end_year")
    run_date = models.DateField(db_column="run_date")
    student_count = models.IntegerField(db_column="students")

Я пробовал аннотировать дополнительные поля, где я привожу результаты к CharField или IntegerField, но они (ожидаемо) выдают ошибку, когда попадают на что-то, что не конвертируется.

    all_enrollments = (
        Enrollment.objects.filter(
            location_id__in=location_ids,
            end_year=today.year,
        )
        .order_by("-run_date")
        .annotate(first_letter_group=Substr("grade", 1, 1))
    )

    ordered_enrollment_list = (
        all_enrollments.annotate(
            number_field=Cast(
                "first_letter_group", output_field=IntegerField()
            ),
            str_field=Cast(
                "first_letter_group", output_field=IntegerField()
            ),
        )
        .order_by("-str_field", "number_field")
    )

Я не могу понять, как это сделать без функциональности __regex, которую наша БД не поддерживает.

Это не очень красиво, но, насколько я понял ваш вопрос, это делает свою работу

numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']

ordered_enrollment_list = (
        all_enrollments.annotate(
            number_field=Case(
                  When(first_letter_group__in=numbers, then=Cast(F('first_letter_group'), IntegerField())),
                  default=Value(0),
                  output_field=IntegerField()
               ),
            str_field=Case(
                  When(first_letter_group__in=numbers, then=Value(False)),
                  default=Cast(F('first_letter_group'), CharField()),
                  output_field=CharField()
               ),
        )
        .order_by('-str_field', 'number_field')
    )
Вернуться на верх