Django管理员中的伪形式,在保存时生成一个json对象

hoo*_*ter 11 django django-forms django-admin

我有一个带有json对象字段的模型.该对象在网站上用于控制一些css变量等.

现在在管理员中,我有一个文本字段,用户可以在其中保存json对象.我想显示一个包含所有属性的表单,在保存时,将生成一个json对象.

基本上,用户看到并存储数据,如下所示:

{
    "name":"hookedonwinter",
    "user-id":123,
    "basics":{
        "height":150,
        "weight":150
        }
}
Run Code Online (Sandbox Code Playgroud)

而且我宁愿让用户看到这个:

Name: <input field>
User Id: <input field>
Height: <input field>
Weight: <input field>
Run Code Online (Sandbox Code Playgroud)

并且数据仍然存储在json中.

任何指导将不胜感激.链接到文档解释这一点,倍加赞赏.

谢谢!

Mar*_*tis 26

理念

基本上你需要做的是将你的JSON渲染到字段中.

  1. 为存储JSON数据的模型创建字段.
  2. 创建表单域
  3. 创建小部件:
    1. 将字段呈现为多个输入
    2. 从POST/GET获取数据并将其转换回JSON

您还可以通过覆盖TextField的小部件来跳过步骤1,2.

文档链接

概念证明

我尝试编写这个解决方案,这里的解决方案对我有用而没有一些边缘情况.

fields.py

import json

from django.db import models
from django import forms
from django import utils
from django.utils.translation import ugettext_lazy as _


class JSONEditableField(models.Field):
    description = _("JSON")

    def formfield(self, **kwargs):
        defaults = {'form_class': JSONEditableFormField}
        defaults.update(kwargs)
        return super(JSONEditableField, self).formfield(**defaults)

class JSONEditableWidget(forms.Widget):
    def as_field(self, name, key, value):
        """ Render key, value as field """
        attrs = self.build_attrs(name="%s__%s" % (name, key))
        attrs['value'] = utils.encoding.force_unicode(value)
        return u'%s: <input%s />' % (key, forms.util.flatatt(attrs))

    def to_fields(self, name, json_obj):
        """Get list of rendered fields for json object"""
        inputs = []
        for key, value in json_obj.items():
            if type(value) in (str, unicode, int):
                inputs.append(self.as_field(name, key, value))
            elif type(value) in (dict,):
                inputs.extend(self.to_fields("%s__%s" % (name, key), value))

        return inputs

    def value_from_datadict(self, data, files, name):
        """
        Take values from POST or GET and convert back to JSON..
        Basically what this does is it takes all data variables
        that starts with fieldname__ and converts
        fieldname__key__key = value into json[key][key] = value
        TODO: cleaner syntax?
        TODO: integer values don't need to be stored as string
        """
        json_obj = {}

        separator = "__"

        for key, value in data.items():
            if key.startswith(name+separator):
                dict_key = key[len(name+separator):].split(separator)

                prev_dict = json_obj
                for k in dict_key[:-1]:
                    if prev_dict.has_key(k):
                        prev_dict = prev_dict[k]
                    else:
                        prev_dict[k] = {}
                        prev_dict = prev_dict[k]

                prev_dict[dict_key[-1:][0]] = value

        return json.dumps(prev_dict)


    def render(self, name, value, attrs=None):
        # TODO: handle empty value (render text field?)

        if value is None or value == '':
            value = '{}'

        json_obj = json.loads(value)
        inputs = self.to_fields(name, json_obj)

        # render json as well
        inputs.append(value)

        return utils.safestring.mark_safe(u"<br />".join(inputs))

class JSONEditableFormField(forms.Field):
    widget = JSONEditableWidget
Run Code Online (Sandbox Code Playgroud)

models.py

from django.db import models
from .fields import JSONEditableField

class Foo(models.Model):
    text = models.TextField()
    json = JSONEditableField()
Run Code Online (Sandbox Code Playgroud)

希望这会有所帮助,以下是它的外观: 结果