我正在寻找一种将 Python 列表作为逗号分隔字符串存储在数据库中的解决方案。在做了一些研究并得出结论认为 Django 没有像这样开箱即用的东西后,我决定自己写这个。
这是我想出的模型字段:
class CommaSeparatedStringsField(models.CharField):
def from_db_value(self, value, *args):
if not value:
return []
return value.split(',')
def to_python(self, value):
if isinstance(value, list):
return value
return self.from_db_value(value)
def get_prep_value(self, value):
return ','.join(value)
def value_to_string(self, obj):
return self.get_prep_value(self.value_from_object(obj))
def formfield(self, **kwargs):
defaults = {'form_class': ListField}
defaults.update(kwargs)
return models.Field.formfield(self, **defaults)
Run Code Online (Sandbox Code Playgroud)
非常简单的东西,到目前为止,没有问题。
与此模型字段关联的表单字段和小部件应该是一个多选框。列表中的每个元素都是选择字段中的一个选项。
如果您想知道我为什么要这样,它是用于Bootstrap Tags Input 的,这是一个用于输入“标签”(多个值)的输入小部件。这可以使用文本框工作,但我更愿意在 Python 中将此字段表示为列表。
现在有了 MultipleChoiceField(它使用 MultipleSelect 小部件),但它有一个预定义的选项列表。这不是我想要的,在我的情况下,选项是数据,我不关心选定的选项。
所以我写了一个自定义表单字段和小部件,它继承了上述类:
class ListWidget(SelectMultiple):
def render_options(self, options):
output = []
for option_value, option_label in options:
output.append(self.render_option([], option_value, option_label))
return '\n'.join(output)
class ListField(MultipleChoiceField):
widget = ListWidget
def prepare_value(self, value):
return [(x, x) for x in value]
Run Code Online (Sandbox Code Playgroud)
我覆盖了 SelectMultiple 的 render_options() 以将数据呈现为选项而不是预定义的选择,并且我覆盖了 MultipleChoiceField 的验证以删除选择检查和 prepare_value 以将列表转换为元组列表(option_value 和 option_label)。
这在大多数情况下有效。问题是它在提交为空时似乎没有保存该字段,我不明白为什么。当我使用 MultipleChoiceField 本身而不是我编写的自定义表单字段和小部件时,也会发生这种情况。
我试图使用调试器缩小范围,但我找不到这里到底发生了什么。我可以看到表单的清理数据具有正确的值([],空列表),但是当该字段被保存时,它具有旧值。
我在这里俯瞰什么?
| 归档时间: |
|
| 查看次数: |
6348 次 |
| 最近记录: |