Как отсортировать набор вопросов по выбору атрибутов
У меня есть модель на Django (5.0.4) с выбираемым месяцем и годом, например, так:
class Item(models.Model):
MONTHS_CHOICES = [
('JANUARY', 'January'),
('FEBRUARY', 'February'),
('MARCH', 'March'),
('APRIL', 'April'),
('MAY', 'May'),
('JUNE', 'June'),
('JULY', 'July'),
('AUGUST', 'August'),
('SEPTEMBER', 'September'),
('OCTOBER', 'October'),
('NOVEMBER', 'November'),
('DECEMBER', 'December')
]
month = models.CharField(max_length=9, choices=MONTHS_CHOICES, default="JANUARY", db_index=True)
year = models.IntegerField(default=0)
(...)
Если я попытаюсь упорядочить элементы по месяцам и годам Item.objects.all().order_by("-year", "month")
.
Логически месяцы будут упорядочены в алфавитном порядке.
Что я могу сделать, чтобы предметы были заказаны в том же порядке, в котором у меня есть месяцы на MONTHS_CHOICES
?
Вариант B - просто переделать модели, включив в них DateField
только год и месяц, как этот вопрос здесь, и упорядочить их по этому полю
Я также пробовал решения на этой странице, но мне ничего не помогло.
У меня еще не было возможности проверить это на практике, но я предполагаю использовать название месяца в качестве "ключа" в словаре, где соответствующее "значение" - это порядковое значение соответствующего месяца (например, Jan -> 1, Feb -> 2, и т.д.)
Вот мои мысли о том, как это может выглядеть:
class Item(models.Model):
MONTHS_CHOICES = [
('JANUARY', 'January'),
('FEBRUARY', 'February'),
('MARCH', 'March'),
('APRIL', 'April'),
('MAY', 'May'),
('JUNE', 'June'),
('JULY', 'July'),
('AUGUST', 'August'),
('SEPTEMBER', 'September'),
('OCTOBER', 'October'),
('NOVEMBER', 'November'),
('DECEMBER', 'December')
]
MONTHS_ORDER = {
'JANUARY': 1,
'FEBRUARY': 2,
'MARCH': 3,
'APRIL': 4,
'MAY': 5,
'JUNE': 6,
'JULY': 7,
'AUGUST': 8,
'SEPTEMBER': 9,
'OCTOBER': 10,
'NOVEMBER': 11,
'DECEMBER': 12
}
month = models.CharField(max_length=9, choices=MONTHS_CHOICES, default="JANUARY", db_index=True)
month_numeric = models.IntegerField(editable=False, db_index=True)
year = models.IntegerField(default=0)
def (self, *args, **kwargs):
self.month_numeric = self.MONTHS_ORDER[self.month]
super().save(*args, **kwargs)
ПРИМЕЧАНИЕ: Если у вас уже есть данные в вашей БД, вам нужно будет отредактировать ваш файл миграции, чтобы установить это автоматически для объектов, уже хранящихся в вашей БД. Опять же, это не проверялось, но я предполагаю что-то вроде следующего:
def populate_month_numeric(apps, schema_editor):
Item = apps.get_model('YOUR APP NAME - CHANGE THIS!', 'Item')
for item in Item.objects.all():
item.month_numeric = Item.MONTHS_ORDER[item.month]
item.save()
Затем, запустив makemigrations
, откройте созданный файл миграции и в поле Migration
класса operations
добавьте в конце следующее:
migrations.RunPython(populate_month_numeric)
Затем, конечно же, выполните функцию migrate
, и ваши запросы должны быть такими, как показано ниже:
items = Item.objects.all().order_by("-year", "month_numeric")
Как я уже сказал, сам я еще не запускал этот код, но этот аспект отображения 'Key' -> 'Value' - это то, как я решал подобные проблемы в прошлом!
Если у вас есть свободный выбор в поле DB, то не используйте CharField с названием месяца. Используйте IntegerField с вариантами выбора:
MONTHS_CHOICES = [
( 1, 'January'),
( 2, 'February'),
( 3, 'March'),
...
]
Числа произвольные, если по какой-то причине (налоговые годы в Великобритании!) вы хотите, чтобы апрель был 1, а март - 12, закодируйте это.
Для шаблонов, отображающих это поле, или кода Python, где требуется название месяца, используйте
{{ item_instance.get_month_display }}
or в Python
month_name = item_instance.get_month_display()