代码之家  ›  专栏  ›  技术社区  ›  HardQuestions

将Django JSONField处理为YAML

  •  1
  • HardQuestions  · 技术社区  · 6 年前

    在Django中,当前Postgres的JSONField模型字段在CharField表单字段中显示为纯JSON文本。

    我希望在CharField中以YAML文本的形式呈现数据(同时在内部保持JSON格式),并在保存时将其转换回JSON,如:

    yaml.dump(json.loads(value))

    当前:

    Expected

    必要: Was

    如何做到这一点?

    谢谢

    1 回复  |  直到 6 年前
        1
  •  0
  •   HardQuestions    6 年前

    解决方案是将JSONField(模型和表单)子类化,并用yaml替换json。单独包装: https://github.com/mike-tk/django-yamlfield

    from django.contrib.postgres import fields, forms
    import yaml
    from django.utils.translation import gettext_lazy as _
    
    class InvalidYAMLInput(str):
        pass
    
    
    class YAMLString(str):
        pass
    
    
    class YAMLFormField(forms.JSONField):
        default_error_messages = {
            'invalid': _("'%(value)s' value must be valid YAML."),
        }
    
        def to_python(self, value):
            if self.disabled:
                return value
            if value in self.empty_values:
                return None
            elif isinstance(value, (list, dict, int, float, YAMLString)):
                return value
            try:
                converted = yaml.load(value)
            except yaml.YAMLError:
                raise forms.ValidationError(
                    self.error_messages['invalid'],
                    code='invalid',
                    params={'value': value},
                )
            if isinstance(converted, str):
                return YAMLString(converted)
            else:
                return converted
    
        def bound_data(self, data, initial):
            if self.disabled:
                return initial
            try:
                return yaml.load(data)
            except yaml.YAMLError:
                return InvalidYAMLInput(data)
    
        def prepare_value(self, value):
            if isinstance(value, InvalidYAMLInput):
                return value
            return yaml.dump(value, default_flow_style=False)
    
    
    class YAMLField(fields.JSONField):
        def formfield(self, **kwargs):
            defaults = {'form_class': YAMLFormField}
            defaults.update(kwargs)
            return super().formfield(**defaults)