Псевдо-форма в Django admin, которая генерирует объект json при сохранении
У меня есть модель с полем для объекта json. Этот объект используется на сайте для управления некоторыми переменными css, среди прочего.
Прямо сейчас в admin у меня есть текстовое поле, в котором пользователь может сохранить объект 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.
Любое руководство будет оценено. Ссылки на документы, объясняющие это, ценятся вдвойне.
Спасибо!
7 ответов:
Идея
В основном то, что вам нужно сделать, это визуализировать ваш JSON в поля.
- создайте поле для модели, в котором хранятся данные JSON.
- создать поле формы
- Создать виджет, который:
- отображение полей в виде нескольких входных данных
- берет данные из POST / GET и преобразует их обратно в JSON
Вы также можете пропустить шаги 1, 2, переопределив виджет для текстового поля.
Ссылки на документацию
- виджеты: https://docs.djangoproject.com/en/1.3/ref/forms/widgets/
- Django код для справки как создавать виджеты: https://code.djangoproject.com/browser/django/trunk/django/forms/widgets.py
Доказательство понятия
Я попробовал кодировать это решение, и вот решение, которое работало для меня без некоторых крайних случаев.
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 = JSONEditableWidgetModels.py
from django.db import models from .fields import JSONEditableField class Foo(models.Model): text = models.TextField() json = JSONEditableField()Надеюсь, что это поможет, и вот как это выглядит:
У меня была аналогичная задача. Я решил эту проблему, создав виджет формы Django. Вы можете попробовать его для ваших приложений django-SplitJSONWidget-form
Интересный вопрос! Я хотел бы видеть хорошее и элегантное решение для этого :) Но мне кажется, что django-admin не подходит для вашей задачи. Я бы попробовал поиграть с формами. Что-то вроде этого:
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 }}
Это выглядит просто так:
#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В конце концов, просто установите эту форму в качестве формы для администратора.
P.S.: Также вы можете написать свой собственный виджет для формы, который преобразует объект json в поля на уровне js и имеет текстовую область внизу.
В основном это звучит так, как будто вы хотите пользовательский виджет для вашего текстового поля. фрагмент на этой странице дает пример того, как визуализировать пары ключ-значение json. Даже если он не совсем соответствует вашим потребностям, особенно если вложенный json добавляет некоторую сложность, он, возможно, может дать вам некоторые идеи.
Что касается чистого хранения и извлечения объектов json в Python dicts, существует несколько многоразовых реализаций JSONField, таких как Эта. Возможно, вы захотите добавить его к смесь.
Django-submodel может помочь вам, хотя теперь он не может представлять слоистый ключ-значение.
Жаль упустить такую огромную награду =p

Comments