웹프로그래밍/Django

[Django] summernote, 에디터 사용하기

ssung.k 2019. 8. 13. 15:21

 

 

일반적으로 브라우저에서 지원해주는 Input 은 기능이 부족하다고 생각해서 다른 에디터를 사용하고자 하였습니다. 기존에 CKEditor 를 알고 있어서 사용해보았는데 결정적으로 file 에 대해서 부분 유료라서 어쩔 수 없이 다른 걸 찾아보았습니다. 그러던 중 summernote 를 찾게 되었고 적용이나 기능 면에서 더 효율적이라 생각되어 사용 방법을 정리해보았습니다.

WYSIWYG 란?

WYSIWYG 는 위지위그라고 읽으며 What You See Is What You Get 의 줄임말로서 '보는대로 얻는다' 라는 의미입니다. 다시 말해서 html 처럼 따로 css 문법을 적용해서 디자인을 편집하는 것이 아니라 문서 편집 과정에서 화면에 포맷된 낱말, 문장이 출력물과 동일하게 나오는 방식을 말합니다. summernote 도 WYSIWYG 의 일종이라고 볼 수 있습니다.

 

설치 및 기본 설정

summernote 를 CDN 방식으로 jQuery 를 이용해서 적용할 수 있지만 django app으로 개발이 되어있어서 쉽게 설치가 가능합니다. pip 를 통해 설치해주시고,

pip install django-summernote

INSTALLED_APPS 에 추가해줍니다.

# settings.py

INSTALLED_APPS = [
    # 생략
    'django_summernote',
]

 

다음으로는 전체 urls 에 summernote 를 사용할 수 있도록 include 해줍니다.

# config/urls.py

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
		# 생략
    path('summernote/', include('django_summernote.urls')),
]

 

이미지 업로드를 위해서 media 설정도 해주도록 합시다.

# settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')

 

summernote 적용

Post 라는 모델을 정의하고 이에 대한 예시를 살펴보겠습니다.

# models.py

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=10)
    content = models.TextField()

    def __str__(self):
        return self.title

 

summernote 를 적용하기 위해서는 forms.py 를 사용합니다. forms 이 낯설다면 이전 글을 참고해주시길 바랍니다.

form 알아보기

 

[Django] Form 과 validations

django 로 프로젝트를 진행하면서 예상 외의 난관에 봉착했습니다. 회원가입을 구현하는 과정에서 회원가입의 input 이 너무나도 많았습니다. 이를 하나씩 input 태그를 만들어주고 views 에서 값을 하나씩 받아오..

ssungkang.tistory.com

# forms.py

from django import forms
from .models import Post

from django_summernote.widgets import SummernoteWidget

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']
        widgets = {
            'content': SummernoteWidget(),
        }

이제 form 을 띄워주기만 하면

<form action="" method="POST">
    {% csrf_token %}
    <table>
        {{form.as_table}}
    </table> 
    <input type="submit" value="제출">
</form>

다음과 같이 여러 기능을 가진 editor를 사용하실 수 있습니다.

글을 쓰고 저장을 하면 스타일이 html 로 바뀌어 있는 그대로 보여주게 됩니다.

 

따라서 templates filter, safe 를 사용해서 tag escape 를 방지할 수 있습니다.

<h1>메인 화면</h1>

<a href="{% url 'post_create' %}">글쓰기</a>
<hr>
{% for post in post_list %}
    <h3>
        <a href="{% url 'post_detail' post.id %}">
            {{ post.title }}
        </a>
        
    </h3>
    <div>{{ post.content | safe }}</div>
    <a href="{% url 'post_edit' post.pk %}">수정</a>
    <hr>
{% endfor %}

 

summernote custom

settings.py 에서 SUMMERNOTE_CONFIG 에 다음과 같은 설정사항이 default 로 있습니다. 이를 오버라이딩 하여 사용할 수 있습니다.

# settings.py

SUMMERNOTE_CONFIG = {
    # Using SummernoteWidget - iframe mode, default
    'iframe': True,

    # Or, you can set it as False to use SummernoteInplaceWidget by default - no iframe mode
    # In this case, you have to load Bootstrap/jQuery stuff by manually.
    # Use this when you're already using Bootstraip/jQuery based themes.
    'iframe': False,

    # You can put custom Summernote settings
    'summernote': {
        # As an example, using Summernote Air-mode
        'airMode': False,

        # Change editor size
        'width': '100%',
        'height': '480',

        # Use proper language setting automatically (default)
        'lang': None,

        # Or, set editor language/locale forcely
        'lang': 'ko-KR',
        ...

        # You can also add custom settings for external plugins
        'print': {
            'stylesheetUrl': '/some_static_folder/printable.css',
        },
    },

    # Need authentication while uploading attachments.
    'attachment_require_authentication': True,

    # Set `upload_to` function for attachments.
    'attachment_upload_to': my_custom_upload_to_func(),

    # Set custom storage class for attachments.
    'attachment_storage_class': 'my.custom.storage.class.name',

    # Set custom model for attachments (default: 'django_summernote.Attachment')
    'attachment_model': 'my.custom.attachment.model', # must inherit 'django_summernote.AbstractAttachment'

    # You can disable attachment feature.
    'disable_attachment': False,
    
    # Set `True` to return attachment paths in absolute URIs.
    'attachment_absolute_uri': False,

    # You can add custom css/js for SummernoteWidget.
    'css': (
    ),
    'js': (
    ),

    # You can also add custom css/js for SummernoteInplaceWidget.
    # !!! Be sure to put {{ form.media }} in template before initiate summernote.
    'css_for_inplace': (
    ),
    'js_for_inplace': (
    ),

    # Codemirror as codeview
    # If any codemirror settings are defined, it will include codemirror files automatically.
    'css': (
        '//cdnjs.cloudflare.com/ajax/libs/codemirror/5.29.0/theme/monokai.min.css',
    ),
    'codemirror': {
        'mode': 'htmlmixed',
        'lineNumbers': 'true',

        # You have to include theme file in 'css' or 'css_for_inplace' before using it.
        'theme': 'monokai',
    },

    # Lazy initialize
    # If you want to initialize summernote at the bottom of page, set this as True
    # and call `initSummernote()` on your page.
    'lazy': True,

    # To use external plugins,
    # Include them within `css` and `js`.
    'js': {
        '/some_static_folder/summernote-ext-print.js',
        '//somewhere_in_internet/summernote-plugin-name.js',
    },
}

혹은 다른 방법으로 forms.py 에서도 이를 바꿔 줄 수 있습니다.

# forms.py

from django import forms
from . models import Post

from django_summernote.widgets import SummernoteWidget

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']
        widgets = {
            'content': SummernoteWidget(attrs={'summernote': {'width': '100%', 'height': '400px'}}),
        }


 

Django 3 부터 변경 사항

django 3 부터 클릭재킹에 대한 기본 설정이 변경되어서 추가적인 설정이 필요해졌습니다.

 

django 클릭재킹이란?

 

[Django] Clickjacking Protection, 클릭 재킹 방지

클릭 재킹이란? 클릭재킹 이란 UI 수정 공격이라고도 하며 사용자가 본인이 인식하는 것과 다른 항목을 클릭 하도록 속여서 기밀 정보를 공개하거나 다른 사람이 자신의 컴퓨터를 제어하도록 하는 악의적인 기술입..

ssungkang.tistory.com

X_FRAME_OPTIONS 값을 변경하여 summernote의 로드를 허용할 수 있습니다.

# config/settings.py 

X_FRAME_OPTIONS = 'SAMEORIGIN'