Как сохранить значения произвольного типа в одной модели Django? - PullRequest
3 голосов
/ 21 апреля 2010

Скажите, у меня есть неизвестное количество вопросов.Например:

  • Небесно-голубой [y / n]
  • В какую дату вы родились [дата]
  • Что такое пи [3.14]
  • Что такое большое целое [100]

Теперь на каждый из этих вопросов задается отдельный, но очень специфичный для типа ответ (логическое значение, дата, число с плавающей точкой, int).Родным образом django может с радостью справиться с этим в модели.

class SkyModel(models.Model):
    question = models.CharField("Is the sky blue")
    answer = models.BooleanField(default=False)

class BirthModel(models.Model):
    question = models.CharField("What date were your born on")
    answer = models.DateTimeField(default=today)

class PiModel(models.Model)
    question = models.CharField("What is pi")
    answer = models.FloatField()

Но в этом есть очевидная проблема, заключающаяся в том, что у каждого вопроса есть определенная модель - поэтому, если нам нужно добавить вопрос позже, мне придется изменить базу данных.,Тьфу.Итак, теперь я хочу стать фантазером - Как создать модель, в которой преобразование типа ответа происходит автоматически?

ANSWER_TYPES = (
    ('boolean', 'boolean'),
    ('date', 'date'),
    ('float', 'float'),
    ('int', 'int'),
    ('char', 'char'),
)

class Questions(models.model):
    question = models.CharField(()
    answer = models.CharField()
    answer_type = models.CharField(choices = ANSWER_TYPES)
    default = models.CharField()

Итак, в теории это будет сделано следующим образом:

  • Когда я строю свои представления, я смотрю на тип ответа и проверяю, что я только ввожу это значение.
  • Но когда я хочу вытащить этот ответ обратно, он вернет данные в формате, указанномтип ответаПример 3.14 возвращается как число с плавающей точкой, а не как строка.

Как я могу выполнить такого рода автоматическое преобразование?Или кто-то может предложить лучший способ сделать это?

Спасибо большое !!

Ответы [ 3 ]

5 голосов
/ 21 апреля 2010

Я на самом деле только что столкнулся с такой проблемой, касающейся расширяемых пользовательских настроек Мое решение состояло в том, чтобы сохранить тип на модели в CharField и использовать метод получения, чтобы выполнить преобразование типов с умным использованием __builtin__ и getattr. Это мой код (адаптированный к вашим потребностям):

VALUE_TYPE_CHOICES = (
    ("unicode", "Unicode String"),
    ("int", "Integer"),
    ("bool", "Boolean"),
)

class Setting(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    type = models.CharField(max_length=50, choices=VALUE_TYPE_CHOICES)
    default_value = models.CharField(max_length=127)

def get_setting(user, setting_id):
    profile_setting = #get the user's specific setting value here, not relevant
    type = getattr(__builtin__, profile_setting.setting.type)
    if type is bool:
        return type(int(profile_setting.value))
    else:
        return type(profile_setting.value)

Там есть одна ошибка: bool('0') на самом деле возвращает True, поэтому я решил ввести тип int, а затем тип bool. Есть и другие способы сделать это, например, вместо этого использовать метод literal_eval модуля ast. В целом, модель работает, хотя.

2 голосов
/ 21 апреля 2010

Я бы добавил пользовательский метод в ваш класс вопросов:

def get_converted_answer(self):
  if self.answer_type == 'int':
    return int(self.answer)
  if self.answer_type == 'bool':
    # ...
2 голосов
/ 21 апреля 2010

У вас должно быть все в порядке, просто храня ответы в виде строк. Если мы говорим о принятии данных через Интернет, вы все равно получите свой ввод в виде строки, поэтому вы не потеряете точность, сохранив ее в базе данных в виде строки.

Одной из возможных альтернатив будет включение одного столбца для каждого возможного типа данных, что позволяет им иметь значение null.

class Questions(models.model):
    question = models.CharField(()
    answer = models.CharField()
    answer_type = models.CharField(choices = ANSWER_TYPES)
    int_answer = models.IntegerField(null=True)
    bool_answer = models.NullBooleanField(null=True)
    ... etc. 

Если бы это был я, я бы остановился на одном CharField.

...