Django: Использование словарей в качестве значений для models.Choices

Я пытаюсь сохранить в базе данных периодичность, которая состоит из суммы (например, 2) и единицы измерения (например, месяцы). Пользователю также должен быть предоставлен выбор. Идея состоит в том, чтобы передать это классу, который может использовать эту информацию для вычисления частоты (похоже, но не совсем timedelta, однако это выходит за рамки данного вопроса).

Я подумал, что было бы здорово сохранить эту информацию в виде диктанта в поле JSONField, а при программном извлечении передать ее прямо моему CustomFrequencyClass, отвечающему за вычисления.

Ошибка, которую я неизменно получаю, - TypeError: unhashable type: 'dict'. Или, если я передаю значения в виде кортежей, он скажет мне (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.

class CustomFrequencyClass:
    def __init__(self, *args, **kwargs):
        pass

class Report(models.Model):
    class ReportFrequency(CustomFrequencyClass, models.Choices):
        DAILY = {"days": 1}, "Daily"
        WEEKLY = {"days": 7}, "Weekly"

    frequency = models.JSONField(choices=ReportFrequency.choices, default=ReportFrequency.DAILY)

Если вы работаете с choices=… [Django-doc], Django построит словарь за шторками, чтобы сопоставить значения с текстовым представлением, поэтому в данном случае {'days': 1} - 'Daily', так как ключи словаря должны быть хэшируемыми, а словарь не может быть хэшируемым, так как он может быть изменен, поэтому он не работает.

Однако мы можем обернуть словарь в frozendict [pypi.org], что позволит хэшировать его, но, конечно, под обещанием, что словарь больше не будет обновляться.

from frozendict import frozendict


class Report(models.Model):
    class ReportFrequency(models.Choices):
        DAILY = frozendict({'days': 1}), 'Daily'
        WEEKLY = frozendict({'days': 7}), 'Weekly'

    frequency = models.JSONField(
        choices=ReportFrequency.choices, default=ReportFrequency.DAILY
    )
Вернуться на верх