Published on

Django Admin에서 JSONField 보기 좋게 렌더링하는 방법

Authors

Django의 JSONField는 다양한 데이터를 유연하게 저장할 수 있어서 매우 유용하지만, 기본 Django Admin에서는 가독성이 떨어진다는 단점이 있습니다. 특히 JSON 데이터가 한 줄로 출력되면 유지보수가 어렵고, 실제 운영 중인 데이터를 확인할 때도 불편함을 유발합니다. 결제나 로그성 데이터로 이미 운영중인 데이터를 확인할 때 매우 불편하고 어렵게 느껴졌습니다.

그래서 개선하고자 하였고, 알아본 두 가지 방식(PrettyJsonEncode,PrettyJSONWidget) 중 하나를 선택한 이유와 Django admin JSONField를 개선한 과정을 기록합니다. (두 가지 방식모두 원천 코드는 최하단에 링크를 남겨두었습니다.)

1. PrettyJsonEncode 방식

먼저 검토했던 방식은 PrettyJsonEncode라는 JSON 인코더를 활용하는 방법입니다. 아래는 기본적인 구현 예시입니다.

import json
from django import forms

class PrettyJSONEncoder(json.JSONEncoder):
    def __init__(self, *args, indent, sort_keys, **kwargs):
        super().__init__(*args, indent=2, sort_keys=True, **kwargs)

class MyModelForm(forms.ModelForm):
    json_field = forms.JSONField(encoder=PrettyJSONEncoder)

class MyModelAdmin(admin.ModelAdmin):
    form = MyModelForm

이 방식은 JSON 인코딩 결과를 정렬 및 들여쓰기하여 보여주기 때문에 보기 좋다는 장점이 있습니다.

하지만 다음과 같은 단점이 있었습니다.

  • 이미 존재하는 수많은 모델 폼을 일일이 재정의해야 함
  • 각 필드마다 별도로 forms.JSONField()를 지정해야 함
  • 폼 자체를 커스터마이징해야 해서 유지보수가 어려움

2. PrettyJSONWidget 방식

다른 방식은 커스텀 위젯을 활용하는 방식입니다.

위젯 단위에서 JSON 데이터를 렌더링할 때 정렬과 들여쓰기를 적용하는 방식으로 입니다.

formfield_overrides를 통해 JSONField에만 자동으로 적용되도록 설정할 수 있습니다.

import json
from django.db.models import JSONField
from django.contrib import admin
from django.forms import widgets

class PrettyJSONWidget(widgets.Textarea):
    def format_value(self, value):
        try:
            # ensure_ascii=False 설정으로 한글 깨짐 방지
            value = json.dumps(json.loads(value), indent=2, sort_keys=True, ensure_ascii=False)
            row_lengths = [len(r) for r in value.split('\n')]
            self.attrs['rows'] = min(max(len(row_lengths) + 2, 10), 30)
            self.attrs['cols'] = min(max(max(row_lengths) + 2, 40), 120)
            return value
        except Exception as e:
            return super(PrettyJSONWidget, self).format_value(value)

formfield_overrides = {
    JSONField: {'widget': PrettyJSONWidget}
}

적용 방법 예시

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = formfield_overrides

3. PrettyJSONWidget 방식을 선택한 이유

두 방식 모두 JSON 데이터를 보기 좋게 출력하는 데 효과적입니다.

하지만 실무에서는 다음과 같은 이유로 PrettyJSONWidget 방식을 선택했습니다.

그 이유는 이미 폼을 개별적으로 작성해 둔 곳이 많았기 때문입니다.

PrettyJsonEncode 방식은 일일이 form 클래스를 만들고 연결해야 하는데, 이미 작성된 폼이 많아서 유지보수가 어려웠습니다.

또한 모든 모델에 JSONField가 있는 것이 아니므로, 특정 필드에만 손쉽게 적용할 수 있는 방식이 필요했습니다.

결과적으로 아래와 같은 장점으로 PrettyJSONWidget 방식을 선택했습니다.

  • formfield_overrides 한 줄로 JSONField가 있는 모델에만 적용 가능
  • 유지보수가 훨씬 간편함

즉!! Mixin처럼 쉽게 끼워 넣을 수 있다는 점이 가장 큰 장점이었습니다.

PrettyJSONWidget 적용 후

django admin json field pretty

줄바꿈, 정렬이 되어 있어 읽고 쓰기 훨씬 쉬워진 모습입니다. 또한 로직에 의해 텍스트 영역의 크기가 자동 조절되어 크기걱정을 하지 않아도 됩니다.

레퍼런스 코드만 참고했을 때,한글이 깨지는 문제가 발생할 수 있습니다. 이는 json.dumps()에서 ensure_ascii=True가 기본 설정되어 있기 때문입니다. 이를 해결하려면 아래와 같이 설정하면 됩니다.

json.dumps(json.loads(value), indent=2, sort_keys=True, ensure_ascii=False)

이렇게, Django Admin의 기본 JSONField 렌더링 방식을 개선하는 방법을 채택할 수 있습니다.

4. 레퍼런스

  • hongreat 블로그의 글을 봐주셔서 감사합니다!^^
  • 내용에 잘못된 부분이나 의문점이 있으시다면 댓글 부탁 & 환영 합니다~!
  • (하단의 버튼을 누르시면 댓글을 보거나 작성할 수 있습니다.)
Buy Me A Coffee