利用Django徒手写个静态页面生成工具
每个Geek对折腾自己的博客都有着一份执念
背景介绍
曾经多次在不同的平台写博客,但全部都以失败而告终。去年七月选择微信公众号做为平台开始了又一次的技术分享,庆幸一直坚持到现在,但随着文章发表的越来越多,发现公众号对于PC端很不友好,文章列表没有PC端入口,查看分享很不方便,所以就利用github pages搭建了一个【运维咖啡吧】的网站,分类展示公众号内发表的所有文章以及一些未在公众号发表的琐碎内容
为了追求极速的浏览体验,整个网站采用纯静态的方式构建,这里的静态并不是像Jekyll或者Hexo之类的静态博客框架,而是手写HTML,页面少的时候还能应对,但随着页面越来越多,维护这些内容就成了灾难,好在对Django比较熟悉,于是便动手写了这么一个静态博客页面生成工具
主要功能
网站非常简单,只有三类页面,主页、文章列表页和文章详情页
- 主页用来分类展示公众号内的文章列表
- 文章列表页用来展示网站内文章(一些琐碎的未在公众号发表的文章)的列表
- 文章详情页用来展示具体文章的内容
基于以上的内容分析,其实只需要做两个后台页面,包含几个小功能,画个思维导图

首页为什么要去读取JSON文件呢?主要是因为运维咖啡吧的小程序也同时依赖这个JSON文件,修改一个地方避免维护多份数据
最终实现的效果如下图

接下来介绍下实现这些功能用到的技术或组件
所用技术
读取及写入文件
from django.conf import settings
class FileRun:
def __init__(self):
self.file = settings.BASE_DIR + '/ops_coffee/backends/blog.json'
def read(self):
try:
with open(self.file, 'r', encoding='utf8') as f:
return True, f.read()
except Exception as e:
return False, str(e)
def write(self, content):
try:
with open(self.file, 'w', encoding='utf8') as f:
return True, f.write(content)
except Exception as e:
return False, str(e)
读取及写入文件的操作与Django的View没有太大的关系,所以这里我用了一个单独的类来处理,解释下其中的四个用法
本地文件路径不要硬编码到代码中,尽量采用
settings.BASE_DIR相对路径,或者直接将路径以变量的形式写入到settings文件,例如我们后边要说的生成本地文件的目录就直接在settings中添加了一个变量OPS_COFFEE_GIT_DIR每个方法返回两个参数状态和数据
return True,data,这样在调用这个方法的时候就可以很方便的判断出来这个方法是执行成功还是失败,例如如下代码
state, data = FileRun().read()
if state:
return(data)
读取文件使用
with方法可以在你读取结束后自动执行f.close()关闭文件,避免因打开文件过多造成的资源消耗使用try来避免程序直接抛错,有错误处理机制
JSON格式化
为了展示好看且能实现语法错误提示,采用了jsoneditor插件,这是一个前端的插件,使用非常简单
<div class="col-sm-12" id="jsoneditor" style="height:620px"></div>
<script src="/static/js/jsoneditor.min.js"></script>
<script>
// create the editor
var container = document.getElementById("jsoneditor");
var editor = new JSONEditor(container, {
mode: 'code'
});
// set json
editor.set({{ data|safe }});
</script>
JSON Editor 可以用来查看、编辑、格式化和验证JSON,支持多种模式,例如tree、code、text,当为tree模式时显示树状结构,当为text时显示纯文本,我们这里采用了code模式有行号和颜色,看起来更美观
safe django从view向template传递HTML数据的时候,为了防止html中包含恶意攻击的代码django默认不会渲染HTML,所以需要在template接收到html数据后添加|safe进行渲染
生成HTML
观察会发现整个网站里所有的页面除了中间的内容区域之外,其他的地方都一样,所以我们只需要考虑替换中间的内容就可以了,实际上为了SEO等我们还需要替换title等数据
替换内容生成html文件这里使用了jinja2,我有尝试直接用django的template来渲染,但最终有一些编码问题没有解决,还是采用了jinja2,代码如下
from jinja2 import Template
from django.conf import settings
tmpl = """<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="theme-color" content="#2879d0" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="/css/style.min.css" media="screen" type="text/css" />
<title>{{ title }}</title>
<meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" />
</head>
<body>
<header>
<div class="inner">
<a href="https://ops-coffee.cn/">
<h1>运维咖啡吧</h1>
</a>
<h2>追求技术的道路上,我从不曾停下脚步</h2>
</div>
</header>
<div id="content-wrapper">
<div class="inner clearfix">
<section id="main-content">
{% if havet %}
<h1 id="art-title">{{ title }}</h1>
{% endif %}
{{ content }}
</section>
<aside id="sidebar">
<blockquote class="route">微信公众号</blockquote>
<img border="0" src="/images/z-qrcode.jpg" width="100%" height="100%" alt="ops-coffee" />
<blockquote class="route">归档列表</blockquote>
<div class="sidebar-list"><a href="/"> 精选文章列表</a></div>
<div class="sidebar-list"><a href="/s/"> 日常运维记录</a></div>
</aside>
</div>
</div>
</body>
</html>
"""
kwargs = {
"havet": 0,
"title": "运维咖啡吧",
"description": "追求技术的道路上,我从不曾停下脚步",
"content": content
}
_content = Template(tmpl).render(kwargs)
with open(self.blogDir + '/index.html', 'w', encoding='utf8') as f:
f.write(_content)
tmpl 定义了一个模版,模版内可以使用诸如{{ title }}这样的变量或是{% if havet %}这样的语法
kwargs 定义了一个字典,字典的内容用来替换模版中的变量,字典的key值与模版里边的变量做匹配,匹配到了就用字典的value填充模版
_content 就是最终html的内容,Template(tmpl).render(kwargs)会将kwargs的每个key值与模版中的变量做替换
最后会将html内容写入到html文件
上传GitHub
网站使用github pages搭建,最后需要将生成的html文件上传到github,这里我们使用了gitpython库,gitpython库的用法跟原生git的命令非常像,只是命令中间以.连接
最佳的自动上传步骤应该是:
- 本地生成ssh密钥,并将公钥上传至github,实现本机与ssh之间的无密码上传下载
- 本地创建网站目录,这个目录需要跟settings里边的
OPS_COFFEE_GIT_DIR变量一致,方便直接将html文件生成在这个目录下 - 进入网站目录并使用
git clone拉取github上的代码,注意这里应选择ssh协议的url,例如:git clone git@github.com:ops-coffee/demo.git .,且确定无需输入账号密码即可拉取 - 然后就可以使用以下程序实现自动上传更新到github了,也就是在跑本文所讲的这个生成工具之前需要先做好以上三步
from git import Repo
from django.conf import settings
class GitRun:
def __init__(self):
self.repo = Repo(settings.OPS_COFFEE_GIT_DIR)
def push(self):
try:
self.repo.git.add(A=True)
self.repo.index.commit('ops-coffee')
self.repo.remote(name='origin').push()
return True, True
except Exception as e:
return False, str(e)
Repo() 选择已有的git仓库
git.add 添加本地修改到暂存区,A=True添加到暂存区时包含删除文件的修改
index.commit 提交修改到本地仓库,我这里比较粗糙,统一使用ops-coffee做为log
repo.remote().push() 选择远程分支并提交,name参数表示远程分支的名字
登陆登出
虽然是个简单的个人系统,但最基本的用户认证还是要有的,没有用Django默认的admin页面,但还想使用django提供的auth系统实现登陆登出的话,可以采用下边这种方式
from django.urls import path
from django.contrib.auth.views import LoginView, LogoutView
urlpatterns = [
path('login', LoginView.as_view(template_name='login.html'), name='login-url'),
path('logout', LogoutView.as_view(template_name='login.html'), name='logout-url'),
]
从django.contrib.auth.views下导入LoginView和LogoutView,然后写两条url并指定自己的模版位置就可以使用django的登陆登出功能了,这在一些需要简单认证的系统中非常方便
写在最后
不断折腾的过程才是成长最快的过程,用技术来解决实际的问题是对技术最好的应用
如果你对本篇文章的完整源码感兴趣,可以在微信公众号后台回复“05”获取,当然也非常欢迎加我个人微信一起学习交流

相关文章推荐阅读:
利用Django徒手写个静态页面生成工具的更多相关文章
- 推荐一个静态页面生成工具-mkdocs
最近需要找一个生成api文档的工具,找来找去发现mkdocs特别符合需求. 部署只需python和pip 直接生成静态html 用markdown编写 不需要再markdown里指明日期.标题等信息 ...
- 生成freemarker静态页面的工具类
package cn.bocai.pc.util; import java.io.BufferedWriter;import java.io.File;import java.io.FileOutpu ...
- [Django学习]Ajax访问静态页面
Web开发中常用的一种开发方式是:通过Ajax进行系统的交互,采用Ajax进行交互的时候,更多的时候传输的是JSON格式的数据. 所以开发中我们需要将数据格式转化成JSON,请参见:https://w ...
- hexo 静态页面生成后页面打不开的问题
我这里的原因是4000端口被占用了 *** hexo入门指南教程: 官方文档 用Hexo 3 搭建github blog 做一款hexo主题(进阶) 坑 1 要安装node和git 2 别忘了安装he ...
- 利用ApiPost接口调试与文档生成工具,提升前、后端工作效率
什么是ApiPost? 场景1: 对于我们后端程序员,常常会写一些接口(APIs),但是在前端尚未调用之前,我们必须先自己测试下这个接口是不是正确返回了预定结果.对于一个GET请求的接口还好,我们可以 ...
- php下删除一篇文章生成的多个静态页面
php自定义函数之删除一篇文章生成的多个静态页面,可能有多页的文章,都是需要考虑到的. 复制代码代码如下: //– 删除一篇文章生成的多个静态页面 //– 生成的文章名为 5.html 5_2.ht ...
- HTML页面生成ASPX页面
这个功能是在DTcms Demo网站里面扣出来的一个小功能,他的Demo网站里面可以在HTML写好所有的代码,然后生成一下ASPX页面,就可以访问了.具体的流程下篇文章来分析.这篇文章主要是讲HTML ...
- 使用 gulp-file-include 构建前端静态页面
前言 虽然现在单页面很流行,但是在 PC 端多页面还是常态,所以构建静态页面的工具还有用武之地.最近也看到了一些询问如何 include HTML 文件的问题. 很多时候我们在写静态页面的时候也希望能 ...
- 静态页面参数传递&回调函数写法&快速排序的实现方法
相信很多人都有一种陋习,就是收藏的文章,几乎从来都没有回过头来仔细看过.这次借着这次活动的机会,在<无懈可击的web设计>一书的学习过程中,穿插着讲自己曾经收藏过的,现在觉得还有价值的文章 ...
随机推荐
- DOS中断及程序调用
http://www.cnblogs.com/ynwlgh/archive/2011/12/12/2285017.html
- C#小知识点积累
1.sealed 修饰符 概念: C#提出了一个密封类(sealed class)的概念,帮助开发人员来解决这一问题. 密封类在声明中使用sealed 修饰符,这样就可以防止该类被其它类继承.如果试图 ...
- python单元测试用例
demo1.py #!/usr/bin/python # encoding: utf-8 def hello(): print "i am in demo1" def add(x, ...
- HDU 3896 Greatest TC 双连通分量
题意 给一个连通的无向图,有两种询问: \(a, b, c, d\),问如果删掉\(c,d\)之间的边,\(a,b\)之间是否还连通 \(a, b, c\),问如果删掉顶点\(c\),\(a,b\)之 ...
- leetcode 【 Two Sum 】python 实现
题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...
- Docker与CTF
Docker与CTF 主要是用来搭建环境,漏洞环境,CTF比赛题目复现. docker你可以把它理解为一个vmware. iamges:vmware需要的iso镜像 container:vmware运 ...
- android抓取logcat日志的方法
这几天帮忙测试一个APP,报告结果需要提交日志文件,于是百度了下安卓的获取日志方法,其实很简单,7个步骤搞定,下面把我的总结分享给大家. 1.下载adb工具包 https://pan.baidu.co ...
- ms sqlserver数据库主文件特别大怎么办
因为项目中需要复制数据库,作为外网测试的数据库,但是数据库特别大,复制特别费劲,即使只复制主文件,主文件也特别大. 然后百度了下,发现数据库有个收缩功能,数据库右键——任务——收缩,可以对数据库进行收 ...
- 体验devstack安装openstack
由于公司制度,工作环境是不能直接上网的,所以在工作时间从没有体验过devstack或者其他联网方式安装openstack. 因自己购置了一台不错的主机,因而决定尝试安装一番,经过一段为期不短的内心极度 ...
- mvc与mvp与mvvm
==MVC,MVP和MVVM都是常见的软件架构设计模式,它通过分离关注点来改进代码的组织方式== MVC.MVP和MVVM的相同点和不同点 不同部分是C(Controller).P(Presenter ...