当前位置:   article > 正文

django框架加入simditor富文本编辑器,使用mako进行渲染_django simditor

django simditor

1.安装依赖

django-simditor==0.0.15
  • 1

2.配置

INSTALLED_APPS += (
    'simditor',
)

SIMDITOR_TOOLBAR = [
    'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
    'color', '|', 'ol', 'ul', 'blockquote', 'table', '|', 'link', 'image',
    'hr', '|', 'indent', 'outdent', 'alignment',  # '|', 'markdown'
]
SIMDITOR_UPLOAD_PATH = 'uploads/'
SIMDITOR_IMAGE_BACKEND = 'pillow'
#  图片上传的url
SIMDITOR_CONFIGS = {
    'toolbar': SIMDITOR_TOOLBAR,
    'upload': {
        'url': SITE_URL + '/simditor/upload/',
        'fileKey': 'upload',
        'image_size': 1024 * 1024 * 4   # max image size 4MB
    },
    'emoji': {
        'imagePath': '/static/simditor/images/emoji/'
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

3.生成simditor编辑器form的代码

# -*- coding: utf-8
from __future__ import unicode_literals, absolute_import
from django.conf.urls import include, url
from simditor import utils, image_processing
from .widgets import SimditorWidget
import os
from datetime import datetime

from django.conf import settings
from django.core.files.storage import default_storage

from django.http import JsonResponse

from django.views import generic
from django.views.decorators.csrf import csrf_exempt

# from . import utils, image_processing


class SimditorEditor():
    """Editors should inherit from this. See wiki.editors for examples."""

    # The editor id can be used for conditional testing. If you write your
    # own editor class, you can use the same editor_id as some editor
    editor_id = 'simditor'

    def get_admin_widget(self):

        return SimditorWidget()

    def get_widget(self, instance=None):
        return SimditorWidget()

    def get_urls(self):
        return [url(r'^simditor/', include('simditor.urls'))]

    class AdminMedia:
        css = {'all': (
            'wiki/simditor/styles/simditor.css',
            'wiki/simditor/styles/simditor-markdown.css',
        )}
        js = (
            'wiki/simditor/scripts/jquery.min.js',
            'wiki/simditor/scripts/module.js',
            'wiki/simditor/scripts/uploader.js',
            'wiki/simditor/scripts/hotkeys.js',
            'wiki/simditor/scripts/simditor.js',
            'wiki/simditor/scripts/marked.js',
            'wiki/simditor/scripts/to-markdown.js',
            'wiki/simditor/scripts/simditor-markdown.js',
        )

    class Media:
        css = {'all': (
            'wiki/simditor/styles/simditor.css',
            'wiki/simditor/styles/simditor-markdown.css',
        )}
        js = (
            'wiki/simditor/scripts/jquery.min.js',
            'wiki/simditor/scripts/module.js',
            'wiki/simditor/scripts/uploader.js',
            'wiki/simditor/scripts/hotkeys.js',
            'wiki/simditor/scripts/simditor.js',
            'wiki/simditor/scripts/marked.js',
            'wiki/simditor/scripts/to-markdown.js',
            'wiki/simditor/scripts/simditor-markdown.js',

        )


def get_upload_filename(upload_name):
    # Generate date based path to put uploaded file.
    date_path = datetime.now().strftime('%Y/%m/%d')
    # Complete upload path (upload_path + date_path).
    upload_path = os.path.join(settings.SIMDITOR_UPLOAD_PATH, date_path)
    if getattr(settings, 'SIMDITOR_UPLOAD_SLUGIFY_FILENAME', True):
        upload_name = utils.slugify_filename(upload_name)

    return default_storage.get_available_name(os.path.join(upload_path, upload_name))


def upload_handler(request):
    files = request.FILES

    upload_config = settings.SIMDITOR_CONFIGS.get(
        'upload', {'fileKey': 'upload'})
    filekey = upload_config.get('fileKey', 'upload')

    uploaded_file = files.get(filekey)

    if not uploaded_file:
        retdata = {'file_path': '', 'success': False,
                   'msg': '图片上传失败,无法获取到图片对象!'}
        return JsonResponse(retdata)

    image_size = upload_config.get('image_size')
    if image_size and uploaded_file.size > image_size:
        retdata = {'file_path': '', 'success': False,
                   'msg': '上传失败,已超出图片最大限制!'}
        return JsonResponse(retdata)

    backend = image_processing.get_backend()

    if not getattr(settings, 'SIMDITOR_ALLOW_NONIMAGE_FILES', True):
        try:
            backend.image_verify(uploaded_file)
        except utils.NotAnImageException:
            retdata = {'file_path': '', 'success': False,
                       'msg': '图片格式错误!'}
            return JsonResponse(retdata)

    filename = get_upload_filename(uploaded_file.name)
    saved_path = default_storage.save(filename, uploaded_file)

    url = utils.get_media_url(saved_path)

    is_api = settings.SIMDITOR_CONFIGS.get('is_api', False)
    url = request.META.get('HTTP_ORIGIN') + url if is_api else url

    retdata = {'file_path': url, 'success': True, 'msg': '上传成功!'}

    return JsonResponse(retdata)


class ImageUploadView(generic.View):
    """ImageUploadView."""

    http_method_names = ['post']

    def post(self, request, **kwargs):
        """Post."""
        return upload_handler(request)


UPLOAD = csrf_exempt(ImageUploadView.as_view())

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136

这里有一个坑,由于SimditorWidget()从依赖中引入不识别,我解决的办法:将这个内容所在的文件从依赖中拷贝出来,直接从这个文件引入
widgets.py

"""simditor widgets."""
from __future__ import absolute_import

from django import forms
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.json import DjangoJSONEncoder

from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
from django.utils.html import conditional_escape
from django.utils.functional import Promise

from conf.default import SITE_URL

try:
    # Django >=2.1
    from django.forms.widgets import get_default_renderer

    IS_NEW_WIDGET = True
except ImportError:
    IS_NEW_WIDGET = False

try:
    # Django >=1.7
    from django.forms.utils import flatatt
except ImportError:
    # Django <1.7
    from django.forms.util import flatatt  # pylint disable=E0611, E0401


class LazyEncoder(DjangoJSONEncoder):
    """LazyEncoder."""

    # pylint disable=E0202
    def default(self, obj):
        if isinstance(obj, Promise):
            return force_text(obj)
        return super(LazyEncoder, self).default(obj)


JSON_ENCODE = LazyEncoder().encode

FULL_TOOLBAR = [
    'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
    'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link',
    'image', 'hr', '|', 'indent', 'outdent', 'alignment', 'checklist',
    'markdown', 'fullscreen'
]

DEFAULT_TOOLBAR = [
    'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
    'color', '|', 'ol', 'ul', 'blockquote', 'table', '|', 'link', 'image',
    'hr', '|', 'indent', 'outdent', 'alignment',  # '|', 'markdown'
]

SIMDITOR_UPLOAD_PATH = 'uploads/'
SIMDITOR_IMAGE_BACKEND = 'pillow'
#  我的理解是前端的上传图片请求配置
DEFAULT_CONFIG = {
    'toolbar': DEFAULT_TOOLBAR,
    'cleanPaste': True,
    'tabIndent': True,
    'pasteImage': True,
    'upload': {
        'url': SITE_URL + '/simditor/upload/',
        'fileKey': 'upload',
        'image_size': 1024 * 1024 * 4   # max image size 4MB
    },
}



class SimditorWidget(forms.Textarea):
    """
    Widget providing Simditor for Rich Text Editing.abs
    Supports direct image uploads and embed.
    """

    class Media:
        """Media."""

        css_list = [
            'simditor/styles/simditor.css'
        ]

        if 'emoji' in settings.SIMDITOR_TOOLBAR:
            css_list.append('simditor/styles/simditor-emoji.css')

        if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
            css_list.append('simditor/styles/simditor-fullscreen.min.css')

        if 'checklist' in settings.SIMDITOR_TOOLBAR:
            css_list.append('simditor/styles/simditor-checklist.min.css')

        if 'markdown' in settings.SIMDITOR_TOOLBAR:
            css_list.append('simditor/styles/simditor-markdown.min.css')

        css = {'all': tuple(settings.STATIC_URL + url for url in css_list)}

        jquery_list = ['simditor/scripts/jquery.min.js',
                       'simditor/scripts/module.min.js',
                       'simditor/scripts/hotkeys.min.js',
                       'simditor/scripts/uploader.min.js',
                       # 'simditor/scripts/simditor.min.js',
                       'simditor/scripts/simditor.js',
                       ]

        if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
            jquery_list.append('simditor/scripts/simditor-fullscreen.min.js')

        if 'checklist' in settings.SIMDITOR_TOOLBAR:
            jquery_list.append('simditor/scripts/simditor-checklist.min.js')

        if 'markdown' in settings.SIMDITOR_TOOLBAR:
            jquery_list.append('simditor/scripts/marked.min.js')
            jquery_list.append('simditor/scripts/to-markdown.min.js')
            jquery_list.append('simditor/scripts/simditor-markdown.min.js')

        if 'image' in settings.SIMDITOR_TOOLBAR:
            jquery_list.append('simditor/scripts/simditor-dropzone.min.js')

        if 'emoji' in settings.SIMDITOR_TOOLBAR:
            jquery_list.append('simditor/scripts/simditor-emoji.js')

        js = tuple(settings.STATIC_URL + url for url in jquery_list)

        try:

            js += (settings.STATIC_URL + 'simditor/simditor-init.js',)
        except AttributeError:
            raise ImproperlyConfigured("django-simditor requires \
                     SIMDITOR_MEDIA_PREFIX setting. This setting specifies a \
                    URL prefix to the ckeditor JS and CSS media (not \
                    uploaded media). Make sure to use a trailing slash: \
                    SIMDITOR_MEDIA_PREFIX = '/media/simditor/'")

    def __init__(self, *args, **kwargs):
        super(SimditorWidget, self).__init__(*args, **kwargs)
        # Setup config from defaults.
        self.config = DEFAULT_CONFIG.copy()

        # Try to get valid config from settings.
        configs = getattr(settings, 'SIMDITOR_CONFIGS', None)
        if configs:
            if isinstance(configs, dict):
                self.config.update(configs)
            else:
                raise ImproperlyConfigured(
                    'SIMDITOR_CONFIGS setting must be a dictionary type.')

    def build_attrs(self, base_attrs, extra_attrs=None, **kwargs):
        """
        Helper function for building an attribute dictionary.
        This is combination of the same method from Django<=1.10 and Django1.11
        """
        attrs = dict(base_attrs, **kwargs)
        if extra_attrs:
            attrs.update(extra_attrs)
        return attrs

    def render(self, name, value, attrs=None, renderer=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(self.attrs, attrs, name=name)

        params = ('simditor/widget.html', {
            'final_attrs': flatatt(final_attrs),
            'value': conditional_escape(force_text(value)),
            'id': final_attrs['id'],
            'config': JSON_ENCODE(self.config)
        })

        if renderer is None and IS_NEW_WIDGET:
            renderer = get_default_renderer()

        data = renderer.render(*params) if IS_NEW_WIDGET else render_to_string(*params)

        return mark_safe(data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180

4.form表单部分代码

forms.py文件
class CreateForm(forms.Form, SpamProtectionMixin):

    def __init__(self, request, urlpath_parent, *args, **kwargs):
        super(CreateForm, self).__init__(*args, **kwargs)
	#  富文本字段
    richtext = forms.CharField(
        label=_('Contents'),
        required=False,
        widget=SimditorEditor().get_widget())

article.py文件
class Create(FormView, ArticleMixin):
    form_class = forms.CreateForm
    template_name = "wiki/create.html"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

最后一个问题就是上传图片会出的问题:上传需要url路由,不然上传不识别路由报错,导致上传失败

from django.views.decorators.csrf import csrf_exempt
from .simditor import ImageUploadView  #  从simditor.py导入的

urlpatterns += [
    url(r'^simditor/upload', csrf_exempt(ImageUploadView.as_view())),
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这样就可以识别了
效果:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/595434
推荐阅读
相关标签
  

闽ICP备14008679号