如何在单个Django模型中存储任意类型的值?
假设我有一些不确定数量的问题。例如:
- 天空是蓝色的吗 [是/否]
- 你出生的日期是什么 [日期]
- π(圆周率)是多少 [3.14]
- 什么是大整数 [100]
这些问题的答案类型各不相同,有的是布尔值(是/否),有的是日期,有的是浮点数,还有的是整数。在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 个回答
2
我建议你在你的 Questions 类里添加一个自定义的方法:
def get_converted_answer(self):
if self.answer_type == 'int':
return int(self.answer)
if self.answer_type == 'bool':
# ...
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
来处理。
6
我最近遇到了一个关于可扩展用户设置的问题。我的解决办法是把类型存储在模型的一个 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
方法。总的来说,这个方法是有效的。