2010-04-20 2 views
3

Скажите, что у меня неизвестное количество вопросов. Например:Как хранить значения произвольного типа в одной модели Django?

  • небо голубое [г/л]
  • Какая дата были ваши родились [дата]
  • Что такое пи [3,14]
  • Что такое большое МЭГ [100]

Теперь каждый из этих вопросов представляет собой другой, но специфичный для конкретного типа ответ (логический, дата, float, 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() 

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

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

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

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

ответ

5

На самом деле я столкнулся с такой проблемой в отношении расширяемых пользовательских настроек. Мое решение состояло в том, чтобы сохранить тип модели в 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. Есть и другие способы, которые вы можете выполнить, например, используя ast модуль literal_eval. В целом картина работает.

2

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

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

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.

+0

Сохранение его в виде строки это путь, ИМХО, но имея хорошую стратегию для типажей обратно к исходному значению важно. Наличие разных полей для каждого типа ответов просто звучит необычно. –

2

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

def get_converted_answer(self): 
    if self.answer_type == 'int': 
    return int(self.answer) 
    if self.answer_type == 'bool': 
    # ... 
+0

Я решил сделать это таким образом, и понял, что смогу получить хитрость и не писать все лишние ifs, используя логику в моем сообщении выше. Конечно, правильная идея. –

+0

Ваш трюк очень приятный. +1 – Bolo

Смежные вопросы