构建个人博客网站(基于Python Flask)
本文由 Ficow Shen 首发于 Ficow Shen's Blog.
文章概览
- 前言
- Sketch
- HTML, CSS, JavaScript
- Python & Flask & MySQL & SQLAlchemy
- Gunicorn & Terminal & Command
- Domain name
- Nginx & Certbot
前言
你是否曾经尝试过搭建个人博客网站?
Hugo, Hexo,WordPress 这些耳熟能详的产品,你是否也曾经试用过?
这些产品可以让你极速搭建个人博客网站,而且你不需要了解太多技术细节。
如果你只是想有一个简单的博客网站
,只是希望能够进行内容创作、发表
,那么我建议你使用那些产品
并停止阅读这篇文章
。
如果你想DIY你的博客
、想更深入地了解一个博客系统
、想学习一些Web和后端技术
,那么我建议你继续阅读,然后 自己搭建一个博客网站!
为何选择 Python
和 Flask
进行后端开发?
- Python
简单易学
- 对脚本语言感兴趣,通过学习 Python 来熟悉
脚本语言
- Flask 是一个知名且
被广泛应用
的后端开发框架,社区非常活跃
- Python 和 Flask 都有
丰富的第三方库
当然,除了 Python,你也可以选择 PHP, Golang 等作为后端开发语言。
在学习开始之前,我向你推荐一个网站:Learn X in Y minutes 。
正如网站名称说的那样,你可以在Y分钟内学习X。该站可以加快你的学习进程,让你尽快看到内容的全貌。
Sketch
使用 Sketch,主要是为了设计博客页面
。
当然,也可以用 PhotoShop 这种类似的软件。
然后,你就可以参考别人的个人博客页面,然后设计自己的博客页面的版式、配色等等。
也许有人会问,有很多现成的主题可以用,为什么还要自己设计呢?
如果你想学习和应用 Web技术
,尤其是 CSS 中的 Selector、Flexbox,那么自己写就可以让你的学习效果更好。
如果你不感兴趣,可以跳过这一步,直接去用别人造好的轮子即可。
如果你觉得 Sketch 实在太贵,请看这里。
Sketch 是个很优秀的产品,请您支持正版
~
HTML, CSS, JavaScript
HTML 示例:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
CSS 示例:
body {
background-color: lightblue;
}
h1 {
color: white;
text-align: center;
}
p {
font-family: verdana;
font-size: 20px;
}
JavaScript 示例:
document.getElementById("demo").innerHTML = "Hello JavaScript";
在开始学习之前,我在知乎了解了 零基础如何迅速学习前端?。
然后,在 菜鸟教程 看完了 HTML, CSS, JavaScript 的基础内容。
相关的基础知识必须过一遍
,甚至几遍!
要确保自己知道这些技术包含哪些内容,然后你后面需要用到的时候,就可以很容易地找到它们并把它们用起来。
除此之外,还在 MDN 单独学习了一些技术点,比如:Flexbox.
以及 阮一峰的网络日志。
看了这些东西之后,就需要实操练习。你可以去找一些博客网站来模仿,通过模仿别人的网站来熟悉前端的布局技术。
其实,要点就是:看基础知识,然后模仿着写,巩固学习效果
。
掌握了这些知识,你就可以写出静态的网页了。
Python & Flask & MySQL & SQLAlchemy
Python 示例:
# -*- coding: UTF-8 -*-
# 该实例输出 Hello World!
print('Hello World!')
让静态网页“活”起来的关键是后端提供的数据支持。
学习 Python & Flask & MySQL
之后,你就可以自己定义后端接口,然后为前端提供数据支持。
学习 Python3,了解 Python 的基础知识点。
掌握了 Python 基础知识之后,就可以开始学习 Flask 了。
点开 Documentation,里面会有 Quickstart,也有 Tutorial。这两个部分,不容错过!
如果觉得阅读英文文档的难度太高,你可以看 Flask Web开发:基于Python的Web应用开发实战。
这本书的资源仅供参考,请您支持正版
~
另外,Flask Tutorial 中使用的是SQLite,但是我建议你使用更好的关系型数据库,比如:MySQL 或者 PostgreSQL。
如何安装和使用这些数据库,你可以参考官方文档或者去搜索引擎找相关的文章来学习。
学完这些内容之后,你基本上就已经学会了:
定义后端接口
、执行数据库CRUD操作
、返回网页数据给前端
、单元测试
以及 基本的网络安全知识
。
把前端和后端的内容结合在一起,网页的内容就任由你来定义。
如果你觉得书写 SQL 语句很烦人,那么我推荐你使用知名的ORM【对象关系映射(Object Relational Mapping)】 框架 SQLAlchemy。
你可以去官方网站找 Tutorial 来快速入门, 比如:SQLAlchemy tutorial
这里有两个示例可供参考。
使用 SQL 语句的示例:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.sql import text
eng = create_engine("mysql://testuser:test623@localhost/testdb")
with eng.connect() as con:
con.execute(text('DROP TABLE IF EXISTS Cars'))
con.execute(text('''CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
Name TEXT, Price INTEGER)'''))
data = ( { "Id": 1, "Name": "Audi", "Price": 52642 },
{ "Id": 2, "Name": "Mercedes", "Price": 57127 },
{ "Id": 3, "Name": "Skoda", "Price": 9000 },
{ "Id": 4, "Name": "Volvo", "Price": 29000 },
{ "Id": 5, "Name": "Bentley", "Price": 350000 },
{ "Id": 6, "Name": "Citroen", "Price": 21000 },
{ "Id": 7, "Name": "Hummer", "Price": 41400 },
{ "Id": 8, "Name": "Volkswagen", "Price": 21600 }
)
for line in data:
con.execute(text("""INSERT INTO Cars(Id, Name, Price)
VALUES(:Id, :Name, :Price)"""), **line)
使用 SQLAlchemy ORM 的示例:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
eng = create_engine('sqlite:///:memory:')
Base = declarative_base()
class Car(Base):
__tablename__ = "Cars"
Id = Column(Integer, primary_key=True)
Name = Column(String)
Price = Column(Integer)
Base.metadata.bind = eng
Base.metadata.create_all()
Session = sessionmaker(bind=eng)
ses = Session()
ses.add_all(
[Car(Id=1, Name='Audi', Price=52642),
Car(Id=2, Name='Mercedes', Price=57127),
Car(Id=3, Name='Skoda', Price=9000),
Car(Id=4, Name='Volvo', Price=29000),
Car(Id=5, Name='Bentley', Price=350000),
Car(Id=6, Name='Citroen', Price=21000),
Car(Id=7, Name='Hummer', Price=41400),
Car(Id=8, Name='Volkswagen', Price=21600)])
ses.commit()
观察后可以发现,使用了 ORM 可以帮助我们专注于业务逻辑。
不用担心 SQL 语句是否打错字,也不用担心它是否能正常执行并返回预期的结果。
Gunicorn & Terminal & Command
学习完 Flask 之后,你已经知道了开发服务器和生产服务器的区别。
为了更好的性能以及安全性,在部署博客系统的时候,你需要使用一个生产服务器。
我选择了 Gunicorn,配置比较简单(入门容易),而且用户群也比较庞大(遇到问题更容易解决)。
参考 Gunicorn 的教程,你可以很容易地完成相关的配置。
Gunicorn 配置示例:
import multiprocessing
bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1
backlog = 2048
worker_class = "gevent"
worker_connections = 1000
daemon = False
debug = True
proc_name = 'gunicorn_demo'
pidfile = './log/gunicorn.pid'
errorlog = './log/gunicorn.log'
使用 Gunicorn 之后,你可以很容易地配置后端应用的访问地址、进程数、日志路径、运行模式等等。
在你打算部署服务器时,你会发现你必须使用 命令行工具
。
首先,启动 Gunicorn 需要执行命令行指令,比如:gunicorn --paste development.ini -b :8080 --chdir /path/to/project
。
然后,连接远程服务器需要使用 SSH, 比如: ssh root@127.0.0.1
。
推荐你学习 Linux 教程 和 Shell 教程 。在部署后台系统到远程服务器的过程中,你会反复用到如 cd
, ls
, vim
等这些命令。所以,学习这些命令是必需的步骤。
如果你还没有购买云服务器,那我推荐你使用 Vultr 的服务器。
优点:便宜、不用备案、轻松部署强力爱国上网等等
缺点:延迟高、经常有黑客来访等等
当然,你也可以购买知名的 AWS、阿里云、腾讯云、UCloud 等等厂商的云服务器。
Domain name
拥有自己的博客的同时,你是不是也希望能够拥有一个特别的网站域名
,比如自己的名字?
现在以 http://ficow.cn 为例来讲解域名相关的知识。
你可以访问 http://www.ficow.cn,也可以访问 http://ficow.cn 。
但是,如果我访问 http://123.ficow.cn 就无法看到正常的页面。为什么呢?
因为我在域名解析页面进行了相应的配置,http://ficow.cn 和 http://www.ficow.cn 都是我希望别人可以正常访问的网页。
我是在 阿里云(原万网) 购买了 ficow.cn
这个域名,当然你也可以选择其他的域名提供商购买域名。
在购买了域名之后,就可以登录控制台进行域名解析
。
在主机记录这一列,我配置了 www
和 blog
。这两个均指向了同一个IP,也就意味着目前我是依靠这一台服务器来处理个人首页 和 博客。
关于域名配置的详细内容,你可以参考域名提供商提供的帮助文档,也可以直接通过搜索引擎寻找答案,这里就不赘述了。
但是,你是不是比较好奇,两个不同的主机记录竟然指向了同一台服务器。服务器是如何对不同的主机记录进行解析的呢? 接下来,Nginx
会告诉你答案~
Nginx & Certbot
Nginx 是一个高性能反向代理服务器,它可以将远程服务器上收到的数据转发给你的后台程序。用它来处理静态文件请求非常方便。
这是一个 Nginx server 的配置 Demo:
server
{
access_log /home/xxx/path/to/project custom_log;
server_name blog.ficow.cn;
charset utf-8;
root /home/xxx/path/to/project;
# Proxy connections to the application servers
location / {
proxy_pass http://0.0.0.0:5000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
client_max_body_size 10M;
}
}
你可以通过简单地配置 Nginx 来监听 80
端口,然后让它根据域名来区分以及转发数据给你的后台程序。
在上面的示例中,Nginx 会把指向 blog.ficow.cn
的访问请求转发给 http://0.0.0.0:5000
, 限制客户端请求中body最大为 10M。
当然,你可以让多个 server_name
都使用这同一套配置。你还可以定义多个 server
,然后对不同的 server_name
进行不同的定制化处理,比如:负载均衡
。
想了解更多关于如何配置 Nginx 的内容,请参考官网文档。
如果你希望你的博客网站支持 HTTPS,我推荐你使用 Certbot。
Certbot 的最大优势就是:免费、易用
,这对于一个个人博客系统来说,简直完美~
在 Ubuntu 系统上安装 Certbot 的示例:
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
自动配置 Nginx 的 SSL 相关参数:
certbot --nginx
编辑定时任务,定期调起 Certbot 去更新 SSL 证书:
crontab -e
插入本行内容,并保存退出,定时任务即可生效
# 分 时 某月中的几号 几月 星期几 *代表任何时候 ,分隔多个相同类型的参数
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew
如果系统默认打开的编辑器不是vim,可以修改环境变量
在~/.profile中加入以下内容,并保存退出
vim ~/.profile
export EDITOR="/usr/bin/vim";
加载更新的EDITOR配置:
source ~/.profile
然后再重新使用crontab -e添加定时更新 SSL 证书的任务即可。
然后,尝试使用HTTPS来访问你的博客吧!