Say I have the unknown number of questions. For example:
Now each of these questions poses a different but very type specific answer (boolean, date, float, int). Natively django can happily deal with these in a model.
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()
But this has the obvious problem in that each question has a specific model - so if we need to add a question later I have to change the database. Yuck. So now I want to get fancy - How do a set up a model where by the answer type conversion happens automagically?
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()
So in theory this would do the following:
How can I perform this sort of automagic transformation? Or can someone suggest a better way to do this?
Thanks much!!
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With