我有一个带有json对象字段的模型。该对象在网站上用于控制一些css变量等。
现在在管理员中,我有一个文本字段,用户可以在其中保存json对象。我想展示一个包含所有属性的表单,在保存后,它将生成一个json对象。
基本上,用户看到并存储数据,如下所示:
{
"name":"hookedonwinter",
"user-id":123,
"basics":{
"height":150,
"weight":150
}
}
我宁愿让用户看到这个:
Name: <input field>
User Id: <input field>
Height: <input field>
Weight: <input field>
并且数据仍然存储在json中。
任何指导都将不胜感激。链接到文档解释这一点,倍加赞赏。
谢谢!
答案 0 :(得分:26)
基本上您需要做的是将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
<强> models.py 强>
from django.db import models
from .fields import JSONEditableField
class Foo(models.Model):
text = models.TextField()
json = JSONEditableField()
希望这会有所帮助,以下是它的外观:
答案 1 :(得分:2)
我有类似的任务。我通过创建Django表单小部件来解决它。您可以为您的应用程序django-SplitJSONWidget-form
试用它答案 2 :(得分:1)
有趣的问题!我希望看到它的优秀和优雅的解决方案:) 但在我看来,django-admin不适合你的任务。我会尝试使用Forms。像这样的Smth:
class HmmForm(forms.Form):
name = forms.CharField(max_length = 128)
user_id = forms.IntegerField()
height = forms.IntegerField()
weight = forms.IntegerField()
def test(request, pk):
form = HmmForm()
if pk > 0:
hmm = Hmm.objects.get(pk = pk)
form = HmmForm( initial = {"name": hmm.name} )
return render_to_response("test/test.html", {"form": form})
然后在模板中简单渲染表单,如您所愿:
{{ form.as_table }} or {{ form.as_p }}
答案 3 :(得分:1)
这看起来很简单:
#Creating custom form
class MyCoolForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = ('field_that_stores_json', )
#field_that_shows_json1 = forms.CharField()
#field_that_shows_jsons = forms.CharField()
def __init__(self, *args, **kwargs):
#Deserizlize field that stores json here
def save(self, *args, **kwargs):
#Serialize fields that shows json here
毕竟,只需将此表单设置为admin的表单即可。
P.S。:你也可以为表单编写自己的小部件,将json对象转换为js级别的字段,并在下面有textarea。
答案 4 :(得分:1)
基本上,您需要为文本字段设置自定义窗口小部件。 The snippet on this page给出了一个如何呈现json键值对的示例。即使它完全不适合你的需求,特别是当你的嵌套json增加了一些复杂性时,它也许会给你一些想法。
对于json对象的纯存储和检索到Python dicts,存在一些可重用的JSONField实现,如this one。您可能希望将其添加到组合中。
答案 5 :(得分:0)
答案 6 :(得分:0)
django-submodel可能会对您有所帮助,但它现在无法表示分层键值。
很遗憾错过这样巨额的赏金= p