Псевдоформа в администраторе Django, который генерирует объект json для сохранения

У меня есть модель с полем для объекта 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.

Любое руководство будет оценено по достоинству. Ссылки на документы, которые объясняют это, вдвойне оценены.

Спасибо!

Ответ 1

Идея

В принципе, вам нужно сделать свой JSON в полях.

  • Создать поле для вашей модели, в котором хранятся данные JSON.
  • Создать поле формы
  • Создайте виджет, который:
    • Отображает поля как несколько входов
    • Принимает данные из POST/GET и преобразует их обратно в JSON

Вы также можете пропустить шаги 1, 2, переопределив виджет для TextField.

Ссылки на документацию

Доказательство концепции

Я пробовал кодировать это решение, и вот решение, которое работало для меня без каких-либо случаев с краями.

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()

Надеюсь, это поможет, и вот как это выглядит: Result

Ответ 2

У меня была схожая задача. Я решил это, создав виджет формы Django. Вы можете попробовать его для своих приложений django-SplitJSONWidget-form

Ответ 3

Интересный вопрос! Я бы хотел увидеть хорошее и элегантное решение для этого:) Но мне кажется, что django-admin не подходит для вашей задачи. Я бы попытался сыграть с Формами. 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 }}

Ответ 4

Это выглядит просто:

#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 и имеет под ним текстовое поле.

Ответ 5

В основном это похоже на то, что вы хотите создать собственный виджет для текстового поля. Отрывок из этой страницы дает пример того, как рендерить пары ключ-значение json. Даже если это не удовлетворяет вашим потребностям полностью, тем более, что ваш вложенный json добавляет некоторую сложность, возможно, он может дать вам некоторые идеи.

Что касается чистого хранения и извлечения json-объектов в Python dicts, существует несколько многоразовых реализаций JSONField, таких как этот. Возможно, вы захотите добавить его в микс.

Ответ 6

Попробуйте использовать YAML в качестве формата ввода для пользователя, а затем десериализовать объект и сериализовать его обратно на json в конце. Django уже имеет сериализаторы для этого.

Ответ 7

django-submodel может помочь вам, хотя теперь он не может представлять собой слоистую ключевую ценность.

Жаль пропустить такую ​​БОЛЬШУЮ баунти = p