利用Django徒手寫個靜態頁面生成工具

每一個Geek對摺騰本身的博客都有着一份執念css

背景介紹

曾經屢次在不一樣的平臺寫博客,但所有都以失敗而了結。去年七月選擇微信公衆號作爲平臺開始了又一次的技術分享,慶幸一直堅持到如今,但隨着文章發表的愈來愈多,發現公衆號對於PC端很不友好,文章列表沒有PC端入口,查看分享很不方便,因此就利用github pages搭建了一個【運維咖啡吧】的網站,分類展現公衆號內發表的全部文章以及一些未在公衆號發表的瑣碎內容html

爲了追求極速的瀏覽體驗,整個網站採用純靜態的方式構建,這裏的靜態並非像Jekyll或者Hexo之類的靜態博客框架,而是手寫HTML,頁面少的時候還能應對,但隨着頁面愈來愈多,維護這些內容就成了災難,好在對Django比較熟悉,因而便動手寫了這麼一個靜態博客頁面生成工具前端

主要功能

網站很是簡單,只有三類頁面,主頁、文章列表頁和文章詳情頁python

  • 主頁用來分類展現公衆號內的文章列表
  • 文章列表頁用來展現網站內文章(一些瑣碎的未在公衆號發表的文章)的列表
  • 文章詳情頁用來展現具體文章的內容

基於以上的內容分析,其實只須要作兩個後臺頁面,包含幾個小功能,畫個思惟導圖git

首頁爲何要去讀取JSON文件呢?主要是由於運維咖啡吧的小程序也同時依賴這個JSON文件,修改一個地方避免維護多份數據github

最終實現的效果以下圖django

接下來介紹下實現這些功能用到的技術或組件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沒有太大的關係,因此這裏我用了一個單獨的類來處理,解釋下其中的四個用法小程序

  1. 本地文件路徑不要硬編碼到代碼中,儘可能採用settings.BASE_DIR相對路徑,或者直接將路徑以變量的形式寫入到settings文件,例如咱們後邊要說的生成本地文件的目錄就直接在settings中添加了一個變量OPS_COFFEE_GIT_DIR微信

  2. 每一個方法返回兩個參數狀態和數據return True,data,這樣在調用這個方法的時候就能夠很方便的判斷出來這個方法是執行成功仍是失敗,例如以下代碼

state, data = FileRun().read()
if state:
    return(data)
  1. 讀取文件使用with方法能夠在你讀取結束後自動執行f.close()關閉文件,避免因打開文件過多形成的資源消耗

  2. 使用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的命令很是像,只是命令中間以.鏈接

最佳的自動上傳步驟應該是:

  1. 本地生成ssh密鑰,並將公鑰上傳至github,實現本機與ssh之間的無密碼上傳下載
  2. 本地建立網站目錄,這個目錄須要跟settings裏邊的OPS_COFFEE_GIT_DIR變量一致,方便直接將html文件生成在這個目錄下
  3. 進入網站目錄並使用git clone拉取github上的代碼,注意這裏應選擇ssh協議的url,例如:git clone git@github.com:ops-coffee/demo.git .,且肯定無需輸入帳號密碼便可拉取
  4. 而後就可使用如下程序實現自動上傳更新到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下導入LoginViewLogoutView,而後寫兩條url並指定本身的模版位置就可使用django的登錄登出功能了,這在一些須要簡單認證的系統中很是方便

寫在最後

不斷折騰的過程纔是成長最快的過程,用技術來解決實際的問題是對技術最好的應用

若是你對本篇文章的完整源碼感興趣,能夠在微信公衆號後臺回覆「05」獲取,固然也很是歡迎加我我的微信一塊兒學習交流


相關文章推薦閱讀:

相關文章
相關標籤/搜索