前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >django admin集成markdown

django admin集成markdown

作者头像
超级大猪
发布2019-11-21 20:28:17
7750
发布2019-11-21 20:28:17
举报
文章被收录于专栏:大猪的笔记

前言

用Markdown语法来写博客,既通用又能装B。弄了一个上午,把自己的网站弄上了markdown编辑器。相当的嗨森。

主要步骤

主体思想是:用js完成一切。

步骤:下载安装 -> 覆盖admin的templates -> 用js代码替换控件 -> 写后台处理文件上传 -> 配置url -> 完工

下载安装

  • 搜索editor.md(不用pip中的django_markdown,因为太老了,一大堆兼容性问题)
  • 把editor.md解压到static/editor.md目录。

覆写目标admin的样式

在django中,可以覆写样式来改变admin的页面。django默认会先从本地的templates文件夹中取样式文件。在templates文件夹下创建文件(链接):

代码语言:javascript
复制
/templates/admin/blog/blogpost/change_form.html

关键内容:

代码语言:javascript
复制
<script src="/static/js/jquery.min.js" type="text/javascript"></script>
<script src="/static/editor.md/editormd.min.js"></script>
<script src="/static/js/blog/blogpost_admin_changeform.js" type="text/javascript"></script>

此文件意在载入editor.md和用户自定义的js。使得可以用blogpost_admin_changeform.js中完成操作。 顺便一说,做网站学点Jquery很重要。

自定义 js 内容

能载入js文件,就可以大显身手了。

blogpost_admin_changeform.js(链接)关键内容:

代码语言:javascript
复制
//处理markdown
var body_parent = $("#id_body").parent();
var body_val = $("#id_body").val();
$("#id_body").remove();
var body = "<div id='bodycontent'><div>";
body_parent.append(body);

testEditor = editormd("bodycontent", {
    width   : "70%",
    value   : body_val,
    name    : "body",
    emoji   : true,
    height  : 640,
    syncScrolling : "single",
    path    : "/static/editor.md/lib/",
    imageUpload    : true,
    imageFormats   : ["jpg", "jpeg", "gif", "png", "bmp", "webp", "txt"],
    imageUploadURL : "/blog/upload?aid="+$("#id_guid").val(),
});

这个文件采用js的方式,将admin生成的body控件替换成了editor.md的控件。

处理显示界面

如果顺利,在admin刷新一下,就能看到美腻的editor.md了。然保存在数据库的文本,还是markdown的格式,在显示页面,需要把markdown转换成html才能正常显示

法1 前台转换

editor.md自带了js库,可以完成markdown to html。具体不表。

法2 后台转换

因为某些原因,我用的是后台转换:

安装Python库

代码语言:javascript
复制
apt-get install markdown
# 尝试这几个命令
# apt-get install python-pygments
# pip install Pygments
apt-get install Pygments #用作代码着色

修改后台代码

代码语言:javascript
复制
blog.body = markdown.markdown(blog.body, extensions=['markdown.extensions.extra',"markdown.extensions.nl2br",'markdown.extensions.sane_lists','markdown.extensions.codehilite'])

附带相关的css

显示页面载入本文附带的css:colorful.css

完成上传功能

创建后台代码

在django中创建upload_file.py(仅用做示例,有安全隐患):

代码语言:javascript
复制
import json
import os
from urllib import quote
from django.http import HttpResponse
import tools.webTools as tools
from ueditor.models import attachment
from django.views.decorators.csrf import csrf_exempt
import random
from models import BlogPost
import dazhu.settings

def convert_name_html_valid(input_name):
    file_name = os.path.split(input_name)
    file_name_arr = os.path.splitext(file_name[1])
    quote_name_arr = [quote(x) for x in file_name_arr]
    quote_name_arr[0] = "%s_%s" % (quote_name_arr[0], random.randint(1, 99))
    return quote_name_arr[0] + quote_name_arr[1]

@csrf_exempt
def upload_files(request):
    class _Result(object):
        def __init__(self):
            self.success = 0
            self.message = ""
            self.url = ""
        def tojson(self):
            return json.dumps(self.__dict__)

    ret = _Result()
    aid = request.GET["aid"]
    tools.debug("upload_files guid", aid)

    fileObj = request.FILES.get('editormd-image-file')
    tools.debug("upload_files fileObj {}".format(fileObj.chunks()))
    source_filename = quote(fileObj.name.encode("utf8"))    
    rnd_file_name = convert_name_html_valid(source_filename)
    tools.debug("upload_files file_name {}".format(rnd_file_name))
    try:
        blog = BlogPost.objects.get(guid=aid)
    except Exception as errors:
        ret.message = "target blog isnt exist {}".format(errors)
        return HttpResponse(ret.tojson())

    tempAttachment = attachment()
    tempAttachment.blog = blog
    tempAttachment.sourceName = source_filename
    tempAttachment.rndName = rnd_file_name      
    tempAttachment.save()

    upload_folder = dazhu.settings.BASE_DIR + "/dazhu/static/upload/"        
    if not os.path.exists(upload_folder):
        os.makedirs(upload_folder)
    file_path = str(upload_folder + rnd_file_name)

    try:
        with open(file_path, 'wb+') as f:
            for chunk in fileObj.chunks():
                f.write(chunk)
    except Exception as errors:
        ret.message = "write file error {}".format(errors)
        return HttpResponse(ret.tojson())

    ret.success = 1
    ret.url = "/static/upload/"+rnd_file_name

    return HttpResponse(ret.tojson())

def get_attachment(request):
    aid = request.GET["aid"]
    attachment_list = BlogPost.objects.get(guid=aid).attachment_set.all()
    ret = []
    for attachment in attachment_list:
        ret.append({"rndName":attachment.rndName,"sourceName":attachment.sourceName})

    return HttpResponse(json.dumps(ret))

修改url

在blog.urls 增加

代码语言:javascript
复制
url(r"^upload$", upload_files),

附录 colorful.css

代码语言:javascript
复制
.codehilite {width:101%; padding: 3px; background-color: #F7F7F7;border: 1px solid #bbbbbb;white-space:normal;}
.codehilite span{word-break: normal;word-wrap:break-word; white-space:normal;}

.codehilite .hll { background-color: #ffffcc }
.codehilite .c { color: #808080 } /* Comment */
.codehilite .err { color: #F00000; background-color: #F0A0A0 } /* Error */
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
.codehilite .o { color: #303030 } /* Operator */
.codehilite .cm { color: #808080 } /* Comment.Multiline */
.codehilite .cp { color: #507090 } /* Comment.Preproc */
.codehilite .c1 { color: #808080 } /* Comment.Single */
.codehilite .cs { color: #cc0000; font-weight: bold } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #808080 } /* Generic.Output */
.codehilite .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0040D0 } /* Generic.Traceback */
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #003080; font-weight: bold } /* Keyword.Pseudo */
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #303090; font-weight: bold } /* Keyword.Type */
.codehilite .m { color: #6000E0; font-weight: bold } /* Literal.Number */
.codehilite .s { background-color: #fff0f0;} /* Literal.String */
.codehilite .na { color: #0000C0 } /* Name.Attribute */
.codehilite .nb { color: #007020 } /* Name.Builtin */
.codehilite .nc { color: #B00060; font-weight: bold } /* Name.Class */
.codehilite .no { color: #003060; font-weight: bold } /* Name.Constant */
.codehilite .nd { color: #505050; font-weight: bold } /* Name.Decorator */
.codehilite .ni { color: #800000; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #F00000; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #0060B0; font-weight: bold } /* Name.Function */
.codehilite .nl { color: #907000; font-weight: bold } /* Name.Label */
.codehilite .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #007000 } /* Name.Tag */
.codehilite .nv { color: #906030 } /* Name.Variable */
.codehilite .ow { color: #000000; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
.codehilite .mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
.codehilite .mi { color: #0000D0; font-weight: bold } /* Literal.Number.Integer */
.codehilite .mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
.codehilite .sb { background-color: #fff0f0 } /* Literal.String.Backtick */
.codehilite .sc { color: #0040D0 } /* Literal.String.Char */
.codehilite .sd { color: #D04020 } /* Literal.String.Doc */
.codehilite .s2 { background-color: #fff0f0 } /* Literal.String.Double */
.codehilite .se { color: #606060; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
.codehilite .sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
.codehilite .si { background-color: #e0e0e0 } /* Literal.String.Interpol */
.codehilite .sx { color: #D02000; background-color: #fff0f0 } /* Literal.String.Other */
.codehilite .sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
.codehilite .s1 { background-color: #fff0f0 } /* Literal.String.Single */
.codehilite .ss { color: #A06000 } /* Literal.String.Symbol */
.codehilite .bp { color: #007020 } /* Name.Builtin.Pseudo */
.codehilite .vc { color: #306090 } /* Name.Variable.Class */
.codehilite .vg { color: #d07000; font-weight: bold } /* Name.Variable.Global */
.codehilite .vi { color: #3030B0 } /* Name.Variable.Instance */
.codehilite .il { color: #0000D0; font-weight: bold } /* Literal.Number.Integer.Long */
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-12-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 主要步骤
  • 下载安装
  • 覆写目标admin的样式
  • 自定义 js 内容
  • 处理显示界面
    • 法1 前台转换
      • 法2 后台转换
        • 安装Python库
        • 修改后台代码
        • 附带相关的css
    • 完成上传功能
      • 创建后台代码
        • 修改url
        • 附录 colorful.css
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档