JsonEditor integration with Django Admin

2019-02-07 10:11发布

问题:

I am working on integrating JSONEditor into the Django admin. There is one field in my model that uses the Postgres JSON and the Tree editor in this library is perfect.

models.py

class Executable(models.Model):
    """ Simplified model for sake of the question."""

    recipe = JSONField(null=True, blank=True)

I've made decent progress (I think) integrating the JSONEditor library within the appropriate create/edit screen in the Django Admin. The data is displayed correctly upon loading but for some reason when I make edits within the JSONEditorWidget the changes are not saved. I'm sure there is some save override that I need to work on, or that I'm missing something obvious, but I'm really not sure where to go from here.

admin.py

import json
from django import forms, utils
from django.contrib import admin

from .models import Executable


class JSONEditorWidget(forms.Widget):
    html_template = """
        <div id='%(name)s_editor_holder'></div>
        <script type="text/javascript">
                var options = {
                    "mode": "tree",
                    "search": true
                };
                var %(name)s_editor = new JSONEditor(container, options);
                var json = %(value)s
                %(name)s_editor.set(json);
                %(name)s_editor.expandAll();

                var json = %(name)s_editor.get(json);
        </script>
        <textarea readonly class="vLargeTextField" cols="40" id="id_%(name)s" name="%(name)s" rows="2" height="20px">%(value)s</textarea>
    """
    def __init__(self, attrs=None, formats=None, defaults=None):
        self.formats = formats
        self.defaults = defaults
        super(JSONEditorWidget, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        if isinstance(value, basestring):  # Edit existing instance
            value = json.loads(value)
        result = self.html_template % {
            'name': name,
            'value': json.dumps(value)
        }
        return utils.safestring.mark_safe(result)


class ExecutableForm(forms.ModelForm):
    recipe = forms.CharField(widget=JSONEditorWidget())    # Kwargs here?

    class Meta:
        model = Executable
        fields = '__all__'

    class Media:
        css = {
            'all': ('http://www.jsoneditoronline.org/app.min.css',)  # TEMP
        }
        js = (
            'http://www.jsoneditoronline.org/app.min.js',   # TEMP
            )


class ExecutableAdmin(admin.ModelAdmin):
    model = Executable
    form = ExecutableForm
    fields = (('request', 'status'), 'recipe')


admin.site.register(Executable, ExecutableAdmin)

回答1:

My solution for Django 1.10.2, jsoneditor#^5.5.9, Postgres 9.5:

models.py

from django.contrib.postgres.fields import JSONField

class Consumer(models.Model):
    data = JSONField(default=dict, db_index=True)

admin.py:

from django import forms
from django.contrib import admin
from django.utils.safestring import mark_safe
from django.template.loader import render_to_string

from .models import Consumer


class JSONEditorWidget(forms.Widget):

    template_name = 'jsoneditor.html'

    def render(self, name, value, attrs=None):
        context = {
            'data': value,
            'name': name
        }

        return mark_safe(render_to_string(self.template_name, context))


class ConsumerForm(forms.ModelForm):

    class Meta:
        model = Consumer
        fields = '__all__'
        widgets = {
            'data': JSONEditorWidget()
        }

    class Media:
        css = { 'all': ('jsoneditor/dist/jsoneditor.min.css',) }
        js = ('jsoneditor/dist/jsoneditor.min.js', )


class ConsumerAdmin(admin.ModelAdmin):
    list_display = ['pk']
    model = Consumer
    form = ConsumerForm

admin.site.register(Consumer, ConsumerAdmin)

jsoneditor.html:

<div id="{{ name }}_editor"></div>

<textarea cols="40" id="id_{{ name }}" name="{{ name }}" rows="10" required="" style="display: none">{{ data }}</textarea>


<script>
    console.log('jsoneditor.html');
    var container = document.getElementById("{{ name }}_editor");

    var options = {
        modes: ['code', 'tree'],
        search: true,

        onChange: function () {
            var json = editor.get();
            document.getElementById("id_{{ name }}").value=JSON.stringify(json);
        }
    };

    var editor = new JSONEditor(container, options);
    var json = {{ data|safe }};
    editor.set(json);
</script>

Blockquote Written with StackEdit.