[Django]-How do I store values of arbitrary type in a single Django model?

6👍

I actually just faced this type of problem regarding extensible user settings. My solution was to store the type on the model in a CharField and use a getter to do the type conversion with a smart use of __builtin__ and getattr. This is my code (adapt for your needs):

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)

There’s one gotcha in there: bool('0') actually returns True, so I chose to typecast to int before typecasting to bool. There are other ways you can accomplish this, like using the ast module’s literal_eval method instead. Overall the pattern works, though.

2👍

You should be fine just storing the answers as strings. If we’re talking about accepting data over the web, you’re going to receive your input as a string anyway, so you’re not losing precision by storing it in the database as a string.

One possible alternative would be to include one column for each possible data type, allowing them to be 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. 

If it were me, I’d stick with a single CharField though.

👤Seth

2👍

I would add a custom method to your Questions class:

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

Leave a comment