Django admin 中的伪形式,在保存时生成 json 对象 [英] Pseudo-form in Django admin that generates a json object on save

查看:16
本文介绍了Django admin 中的伪形式,在保存时生成 json 对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a model with a field for a json object. This object is used on the site to control some css variables, among other things.

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

Right now in the admin, I have a text field where a user can save a json object. I'd like to show a form with all the attributes that, upon saving, will generate a json object.

基本上是用户看到的,数据是这样存储的:

Basically, the user sees, and the data is stored, like this:

{
    "name":"hookedonwinter",
    "user-id":123,
    "basics":{
        "height":150,
        "weight":150
        }
}

我宁愿让用户看到这个:

And I'd rather have the user see this:

Name: <input field>
User Id: <input field>
Height: <input field>
Weight: <input field>

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

and the data still be stored in json.

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

Any guidance would be appreciated. Links to docs that explain this, doubly appreciated.

谢谢!

推荐答案

Idea

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

Idea

Basically what you need to do is render your JSON into fields.

  1. 为您的模型创建存储 JSON 数据的字段.
  2. 创建表单域
  3. 创建具有以下特性的小部件:
  1. Create field for your model that stores JSON data.
  2. Create form field
  3. Create widget that:
  1. 将字段呈现为多个输入
  2. 从 POST/GET 获取数据并将其转换回 JSON

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

You can also skip steps 1, 2 by overriding widget for TextField.

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

I tried coding this solution and here is solution that worked for me without some edge cases.

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

models.py

from django.db import models
from .fields import JSONEditableField

class Foo(models.Model):
    text = models.TextField()
    json = JSONEditableField()

希望这会有所帮助,这是它的外观:

Hope this helps and here is how it looks:

这篇关于Django admin 中的伪形式,在保存时生成 json 对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆