Псевдо-форма в 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.



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



Спасибо!

660   7  

7 ответов:

Идея

В основном то, что вам нужно сделать, это визуализировать ваш JSON в поля.

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

Вы также можете пропустить шаги 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()

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

У меня была аналогичная задача. Я решил эту проблему, создав виджет формы 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, таких как Эта. Возможно, вы захотите добавить его к смесь.

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

Django-submodel может помочь вам, хотя теперь он не может представлять слоистый ключ-значение.

Жаль упустить такую огромную награду =p

Comments

    Ничего не найдено.