用Markdown语法来写博客,既通用又能装B。弄了一个上午,把自己的网站弄上了markdown编辑器。相当的嗨森。
主体思想是:用js完成一切。
步骤:下载安装 -> 覆盖admin的templates -> 用js代码替换控件 -> 写后台处理文件上传 -> 配置url -> 完工
在django中,可以覆写样式来改变admin的页面。django默认会先从本地的templates文件夹中取样式文件。在templates文件夹下创建文件(链接):
/templates/admin/blog/blogpost/change_form.html
关键内容:
<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文件,就可以大显身手了。
blogpost_admin_changeform.js(链接)关键内容:
//处理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才能正常显示。
editor.md自带了js库,可以完成markdown to html。具体不表。
因为某些原因,我用的是后台转换:
apt-get install markdown
# 尝试这几个命令
# apt-get install python-pygments
# pip install Pygments
apt-get install Pygments #用作代码着色
blog.body = markdown.markdown(blog.body, extensions=['markdown.extensions.extra',"markdown.extensions.nl2br",'markdown.extensions.sane_lists','markdown.extensions.codehilite'])
在显示页面载入本文附带的css:colorful.css
在django中创建upload_file.py(仅用做示例,有安全隐患):
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))
在blog.urls 增加
url(r"^upload$", upload_files),
.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 */