Django开发博客6——富文本编辑器

涉及知识点:

  • ckeditor的使用
  • 上传文件save方法的重写,实现图片添加水印功能
  • 前端富文本编辑器的展示逻辑

富文本编辑器实现机制:前端渲染一个新的编辑器界面,隐藏原有的界面,但又能将编写的内容同步到原有的编辑器中,最后由原有的编辑器提交数据
富文本工具:django-ueditor或者django-ckeditor
1.安装配置

pip install django-ckeditor==5.4.0
pip install pillow==5.1.0

# 注册app
'ckeditor',    # 富文本编辑器
'ckeditor_uploader',    # 配置图片上传

# 配置ckeditor
CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'full',
        'height': 300,
        'width': 800,
        'tabSpaces': 4,
        'extraPlugins': 'codesnippet',    # 配置代码插件
    },
}

有关django-ckeditor的详细配置:https://github.com/django-ckeditor/django-ckeditor
2.配置 adminforms.py
针对需求前端展示对应的编辑器界面,隐藏原生的编辑器界面

from django import forms
from ckeditor.widgets import CKEditorWidget
from ckeditor_uploader.widgets import CKEditorUploadingWidget

# 自定义编辑页面中表单元素的样式,调用自动补全接口
class PostAdminForm(forms.ModelForm):
	# 省略其余代码
    # content = forms.CharField(widget=CKEditorWidget(), label='正文', required=True)
    # 这个插件是带图片上传功能的,上面的只能处理文字,上传的同名图片,ckeditor会自动追加随机码区分
    # 这边的required都要写成false,因为用户最终提交的时候,总有两个输入框是空的
    # 原生的content字段设置隐藏,但在数据清洗阶段会接收到最终的内容
    content = forms.CharField(widget=forms.HiddenInput(), label='正文', required=False)
    # 增加额外的forms组件
    # 以下两个组件根据is_md的值通过js进行切换展示
    content_ck = forms.CharField(widget=CKEditorUploadingWidget(), label='正文', required=False)
    content_md = forms.CharField(widget=forms.Textarea(), label='正文', required=False)

    # 配置Meta,在fields中增加新增的字段
    class Meta:
        model = Post
        # 需要自动补全的字段要放到前面
        fields = ('category', 'tag', 'title', 'desc', 'is_md',
                  'content', 'content_ck', 'content_md', 'status')
	
    def __init__(self, instance=None, initial=None, **kwargs):
        # initial为form对象中各字段初始化的值
        initial = initial or {}
        # 如果是编辑一篇文章,那么instance是当前文章的实例
        if instance:
            # 基于instance对象,对新增的两个form层字段进行处理
            if instance.is_md:
                initial['content_md'] = instance.content
            else:
                initial['content_ck'] = instance.content
        super().__init__(instance=instance, initial=initial, **kwargs)

    # 在clean方法中对用户提交的内容进行处理
    def clean(self):
        is_md = self.cleaned_data.get('is_md')
        # 根据is_md的值,判断用户是在哪个编辑器中输入的,然后取对应的内容
        if is_md:
            content_field_name = 'content_md'
        else:
            content_field_name = 'content_ck'
        # 此处content为取到的markdown或ckeditor中的内容
        content = self.cleaned_data.get(content_field_name)
        # 在此处进行空值控制,若为空则返回异常
        if not content:
            self.add_error(content_field_name, '必须填')
            return
        # 将取到的内容赋值给原生的content字段
        self.cleaned_data['content'] = content
        return super().clean()

    class Media:
    	# 引入js文件,控制编辑器的展示逻辑
        js = ('js/post_editor.js',)

3. settings.py 配置上传路劲和访问url

# 分别配置ckeditor图片访问起始url,上传保存路径和存放位置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
CKEDITOR_UPLOAD_PATH = 'article_images'

4.配置接口 urls.py

from django.conf.urls import url, include
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    # 。。。。。。
    # 提供上传图片和浏览图片的接口
    url(r'^ckeditor/', include('ckeditor_uploader.urls')),
    # 配置图片资源的访问,使用django内置的静态文件处理功能提供静态文件服务
    # 在正式环境中,这个功能由Nginx来完成
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

5.对上传的图片添加水印
django默认的存储方式是文件存储,重写save方法即可对上传的文件进行处理
项目主应用下新增 storage.py

from io import BytesIO
from django.core.files.storage import FileSystemStorage
from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image, ImageDraw, ImageFont

# 给上传的图片添加水印
class WatermarkStorage(FileSystemStorage):
    # 重写save方法,添加水印
    def save(self, name, content, max_length=None):
        if 'image' in content.content_type:
            # 将文件对象转为图片对象,然后添加水印
            image = self.watermark_with_text(content, 'Master-Sun', 'red')
            # 再将图片对象转为文件对象
            content = self.convert_image_to_file(image, name)
        # 调用父类的save方法
        return super().save(name, content, max_length=max_length)

    def convert_image_to_file(self, image, name):
        temp = BytesIO()
        image.save(temp, format='PNG')
        file_size = temp.tell()
        return InMemoryUploadedFile(temp, None, name, 'image/png', file_size, None)

    # 字体参数fontfamily可指定本地字体文件路径
    def watermark_with_text(self, file_obj, text, color, fontfamily=None):
        image = Image.open(file_obj).convert('RGBA')
        draw = ImageDraw.Draw(image)
        width, height = image.size
        margin = 10
        if fontfamily:
            font = ImageFont.truetype(fontfamily, int(height / 20))
        else:
            font = None
        textWidth, textHeight = draw.textsize(text, font)
        x = (width - textWidth - margin) / 2    # 计算横轴位置
        y = (height - textHeight - margin)    # 设置纵轴位置
        draw.text((x, y), text, color, font)
        return image

6.修改默认的存储引擎 settings.py

# 修改默认的存储引擎
DEFAULT_FILE_STORAGE = 'blogidea.storage.WatermarkStorage'

7.模型层,新增字段判断使用markdown还是ckeditor,并重写save方法

import mistune
from django.db import models

class Post(models.Model):
	# ......
    # 新增字段,用来标注使用markdown还是富文本编辑器
    is_md = models.BooleanField(default=False, verbose_name='markdown语法')

    # 重写save方法,根据is_md的值切换存储格式
    def save(self, *args, **kwargs):
        if self.is_md:
            self.content_html = mistune.markdown(self.content)
        else:
            # 如果是非markdown语法的,则直接保存content即可(ckeditor已做好转换)
            self.content_html = self.content
        super().save(*args, **kwargs)

7.自定义js文件实现编辑器的展示逻辑

(function ($) {
    var $content_md = $('#div_id_content_md');
    var $content_ck = $('#div_id_content_ck');
    var $is_md = $('input[name=is_md]');
    var switch_editor = function (is_md) {
        if(is_md){
            $content_md.show();
            $content_ck.hide();
        }else{
            $content_ck.show();
            $content_md.hide();
        }
    };
    // is_md监测点击事件,点击后执行switch_editor函数切换编辑器
    $is_md.on('click', function () {
        switch_editor($(this).is(':checked'));
    });
    // 首次加载完页面后执行switch_editor函数确认展示的编辑器
    switch_editor($is_md.is(':checked'));
    // xadmin已经加载了jQuery,可以直接使用,这里的jQuery中的Q要大写
})(jQuery);
  1. adminx.py 中修改layout配置
    # xadmin关于编辑页的布局设置
    form_layout = (
        Fieldset(
            '基础信息',
            Row('title', 'category'),
            'status',
            'tag',
        ),
        Fieldset(
            '内容信息',
            'desc',
            'is_md',
            'content_ck',  # 新增的编辑器,但只会显示一个
            'content_md',
            'content',
        ),
    )

参考:《Django企业开发实战》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值