django-7.django-summernote

summernote

https://github.com/summernote/django-summernote

설치

	pip install django-summernote
settings.py
	INSTALLED_APPS += ('django_summernote', )
	##config 추가
 	SUMMERNOTE_CONFIG = {
    #  # Using SummernoteWidget - iframe mode
    # 'iframe': True,  # or set False to use SummernoteInplaceWidget - no iframe mode

    # # Using Summernote Air-mode
    # 'airMode': False,

    # # Use native HTML tags (`<\b>`, `<\i>`, ...) instead of style attributes
    # 'styleWithSpan': False,

    # # Set text direction : 'left to right' is default.
    # 'direction': 'ltr',

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

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

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

    # # Customize toolbar buttons
    # 'toolbar': [
    #     ['style', ['style']],
    #     ['style', ['bold', 'italic', 'underline', 'clear']],
    #     ['para', ['ul', 'ol', 'height']],
    #     ['insert', ['link']],
    # ],

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

    # # Set `upload_to` function for attachments.
    # 'attachment_upload_to': my_custom_upload_to,

    # # 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': 'blog.myAttachment',  # must inherit 'django_summernote.AbstractAttachment'

    # # Set common css/js media files
    # 'base_css': (
    #     '//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css',
    # ),

    # 'base_js': (
    #     '//code.jquery.com/jquery-1.9.1.min.js',
    #     '//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js',
    # ),

    # 'base_css': (
    #      os.path.join(STATIC_URL, 'plugins/bootstrap-3.3.2-dist/css/bootstrap.min.css'),
    # ),
    # 'base_js': (
    #      os.path.join(STATIC_URL, 'plugins/jquery/jquery-3.2.1.js'),
    #      os.path.join(STATIC_URL, 'plugins/bootstrap-3.3.2-dist/js/bootstrap.min.js'),
    # ),

    # 'default_css': (
    #     os.path.join(STATIC_URL, 'django_summernote/summernote.css'),
    #     os.path.join(STATIC_URL, 'django_summernote/django_summernote.css'),
    # ),
    # 'default_js': (
    #     os.path.join(STATIC_URL, 'django_summernote/jquery.ui.widget.js'),
    #     os.path.join(STATIC_URL, 'django_summernote/jquery.iframe-transport.js'),
    #     os.path.join(STATIC_URL, 'django_summernote/jquery.fileupload.js'),
    #     os.path.join(STATIC_URL, 'django_summernote/summernote.min.js'),
    # ),

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

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

    # # You can disable file upload feature.
    # 'disable_upload': False,

    # # 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',
    # },
    # # You can also add custom settings in `summernote` section.
    # 'summernote': {
    #     'print': {
    #         'stylesheetUrl': '/some_static_folder/printable.css',
    #     },
    # }

urls.py

다른 앱에서 쓸수도 있다는 가정하에 mysite 아래 urls.py 에 추가

from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from . import views  
import blog
from django_summernote.views import editor, upload_attachment
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
	url(r'^$', views.index),
    url(r'^admin/', admin.site.urls),
    url(r'^blog/', include('blog.urls')),
    url(r'^summernote/upload_attachment/$', blog.views.upload_attachment,
    name='django_summernote-upload_attachment'),
	url(r'^summernote/', include('django_summernote.urls')),
]

if settings.DEBUG:
   urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
   urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

models.py

models.py에 attachment 모델을 하나 만들고

	class myAttachment(summer_model.AbstractAttachment):
		author = models.ForeignKey('auth.User')

cmd 창에서 makemigrations 와 migrate 해줌. blog_myattachment 라는 테이블이 생김

	(myvenv) c:\SUUU\python\django\mysite>python manage.py makemigrations
	(myvenv) c:\SUUU\python\django\mysite>python manage.py migrate
views.py (blog.views)

views.upload_attachment 정의

django-summernote의 views.py의 upload_attachment를 그대로 복사해 넣고 아래에 attachment.author 에 request.user를 넣어주었다

 def upload_attachment(request):
	if request.method != 'POST':
		return JsonResponse({
			'status': 'false',
			'message': _('Only POST method is allowed'),
			}, status=400)

	authenticated = \
		request.user.is_authenticated if django.VERSION >= (1, 10) \
		else request.user.is_authenticated()

	if summernote_config['attachment_require_authentication'] and \
			not authenticated:
			return JsonResponse({
				'status': 'false',
				'message': _('Only authenticated users are allowed'),
				}, status=403)

	if not request.FILES.getlist('files'):
		return JsonResponse({
			'status': 'false',
			'message': _('No files were requested'),
			}, status=400)

	# remove unnecessary CSRF token, if found
	kwargs = request.POST.copy()
	kwargs.pop("csrfmiddlewaretoken", None)

	try:
		attachments = []
		for file in request.FILES.getlist('files'):

			klass = get_attachment_model()
			attachment = klass()

			attachment.file = file
			attachment.name = file.name
			attachment.author = request.user

			if file.size > summernote_config['attachment_filesize_limit']:
				return JsonResponse({
					'status': 'false',
					'message': _('File size exceeds the limit allowed and cannot be saved'),
					}, status=400)

			# calling save method with attachment parameters as kwargs
			attachment.save(**kwargs)
			attachments.append(attachment)

		return HttpResponse(render_to_string('django_summernote/upload_attachment.json', {
			'attachments': attachments,
			}), content_type='application/json')

	except IOError:
		return JsonResponse({
			'status': 'false',
			'message': _('Failed to save attachment'),
			}, status=500)

테스트

image