7

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)
Joe Fusaro
  • 847
  • 2
  • 11
  • 23
  • @e4c5 The library is well-documented and available on Github. What makes you think it is not? Btw, I'm still a novice programmer so maybe I've missed something :) – Joe Fusaro May 31 '16 at 22:28
  • I am sorry I misunderstood, i had not used this library before but upon visit to the site there were no visible developer or github links – e4c5 Jun 01 '16 at 00:14
  • @e4c5 no worries, the link is buried in the footer and I could see how you could come to that conclusion. I've updated the link in my post to point to the GitHub repo and not the demo site ( https://github.com/josdejong/jsoneditor/ ) – Joe Fusaro Jun 01 '16 at 02:16

1 Answers1

13

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.

Community
  • 1
  • 1
srgi0
  • 3,319
  • 1
  • 23
  • 20
  • I have been looking for something like this for a while now... thanks – psychok7 Apr 03 '17 at 13:34
  • 1
    Sorry but this didn't work perfectly for me. I had to add minor tweaks esp. converting json text to json `var json = JSON.parse({{ data|safe }});` and renaming `onChange` to `change`. Following is the updated gist https://gist.github.com/rgupta2/761fd987254703673d83426912dc015d – comiventor Jul 10 '18 at 18:16