本博客采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本博客文章必须也遵循署名-非商业用途-保持一致的创作共用协议.
Flask博客源码公开在Github
缘起
最近想读读python方向的源码, 想Pythonic一点, 左右看去, 最后决定读Flask源码.
既然决定读源码, 我认为首先要简单的了解:
- 框架的功能
- 具体接口
- 实现一个简单的轮子.
Flask
我就不多介绍了, 网上一搜一大把, python几大著名Web框架之一, 以其轻量级, 高可扩展性
而著名.
那么我们开始造轮子之旅吧
环境相关:
Mac OS X 10.10.3
Sublime Text 3
FLask 0.10.1
Python 3.4.1 # 请放手Python2.7.8, 拥抱Python3
下文主要内容:
- 介绍Flask搭建博客依赖(随着文章的圆满, 会逐渐添加)
- 搭建博客欢迎页面
- 搭建博客基本框架
Flask安装及相关插件
框架及插件:
- Flask
- Flask-Script
- Flask-WTF
- flask-mongoengine
- Flask-markdown
- virtualenv(版本控制) Virtualenv简明教程
数据库:
- mongo(
了解并会使用一种NoSQL会有很大的好处
)
环境配置
$ pip install virtualenv
$ virtualenv -p /usr/local/bin/python3.4 Flask
$ source Flask/bin/activate
$ pip install Flask, Flask-Script, Flask-WTF, flask-mongoengine
项目骨架
请根据下面的Tree文件结构建立文件夹和文件
$ tree ./
./
├── README.md
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── static/
│ ├── templates/
│ └── views.py
├── config.py
├── manage.py
├── requirements.txt
-
app
为项目核心源码 -
static
为项目静态文件 -
templates
为项目HTML模板
Hello World
国际惯例, 编程第一步...
$ vim app/__init__.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from flask import Flask
app = Flask(__name__) #创建Flask类的实例
app.config.from_object("config") #从config.py读入配置
#这个import语句放在这里, 防止views, models import发生循环import
from app import views, models
views.py用于便携Blog的主逻辑, 和Django中views.py功能相同
$ vim app/views.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template
@app.route('/')
def index():
return "Hello World!"
运用Flask-Script为Flask编写服务器脚本, 产生类似Django的运行方式
$vim manage.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from flask.ext.script import Manager, Server
from app import app
manager = Manager(app)
manager.add_command("runserver",
Server(host="127.0.0.1", port=5000, use_debugger=True))
if __name__ == '__main__':
manager.run()
运行服务器
$ python manage.py flask
浏览器打开http://127.0.0.1:5000/, 正式踏出第一步...
博客搭建框架
编写欢迎页面及样式
$ vim app/templates/welcome.html
{% if title %}
{{ title }} - 雪忆
{% else %}
雪忆
{% endif %}
Andrew Liu 雪 忆
雪忆, 如雪般单纯, 冷静思考.
$ vim app/static/welcome.css
/* reset */
* {
margin: 0;
padding: 0;
}
#wrapper {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
label {
cursor: pointer;
}
label:focus {
outline: none;
}
/* for show */
html, body {
height: 100%;
}
body {
background: url(http://37.media.tumblr.com/f6c67ec2821a91051e4175f8a102e1e2/tumblr_n6rzpcsMk41st5lhmo1_1280.jpg) 50% 50%/cover;
}
p {
margin-bottom: 15px;
}
#info {
display: table;
background: rgba(0, 0, 0, 0.4);
height: 100%;
width: 100%;
}
#info #info-content {
display: table-cell;
vertical-align: middle;
text-align: center;
text-transform: uppercase;
color: #fff;
font-size: 12px;
}
#info #info-content h1 {
color: #fff;
border: 3px solid #fff;
text-align: center;
background: rgba(0, 0, 0, 0.1);
font-size: 22px;
font-weight: normal;
padding: 20px;
margin: 10px;
display: inline-block;
}
#info #info-content h1 strong {
display: block;
font-size: 26px;
}
现在更改views.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template, url_for
@app.route('/')
def index():
return render_template('welcome.html', title="Welcome")
到现在为止我们已经完成了欢迎页面的搭建
编写博客主页框架和样式
$ vim app/templates/base.html
{% if title %}
{{ title }} - 雪忆
{% else %}
雪忆
{% endif %}
{% block content %}{% endblock %}
$vim app/static/base.css
@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,800,700,600,300);
body {
margin:0;
font-family: 'Open Sans', sans-serif;
background: #eee;
}
hr {
background:#dedede;
border:0;
height:1px;
}
.header {
overflow: hidden;
display:block;
position:fixed;
top:0;
margin:0;
width:100%;
height:4px;
text-align:center;
}
.header ul {
margin:0;
padding:0;
}
.header ul li {
overflow:hidden;
display:block;
float:left;
width:20%;
height:4px;
}
.header .cor-1 {
background:#f1c40f;
}
.header .cor-2 {
background:#e67e22;
}
.header .cor-3 {
background:#e74c3c;
}
.header .cor-4 {
background:#9b59b6;
}
.header .cor-5 {
background-color: hsla(10,40%,50%,1);
}
.wrap {
width: 950px;
margin:25px auto;
}
nav.menu ul {
overflow:hidden;
float:left;
width: 650px;
padding:0;
margin:0 0 0;
list-style: none;
color:#fff;
background: #1abc9c;
-webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
-moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
}
nav.menu ul li {
float:left;
margin:0;
}
nav.menu ul a {
display:block;
padding:25px;
font-size: 16px;
font-weight:600;
text-transform: uppercase;
color:#fff;
text-decoration: none;
transition: all 0.5s ease;
}
nav.menu ul a:hover {
background:#16a085;
text-decoration: underline;
}
.sidebar {
width:275px;
float:right;
}
.sidebar .widget {
margin:0 0 25px;
padding:25px;
background:#fff;
transition: all 0.5s ease;
border-bottom: 2px solid #fff;
}
.sidebar .widget:hover {
border-bottom: 2px solid #3498db;
}
.sidebar .widget h2 {
margin:0 0 15px;
padding:0;
text-transform: uppercase;
font-size: 18px;
font-weight:800;
color:#3498db;
}
.sidebar .widget p {
font-size: 14px;
}
.sidebar .widget p:last-child {
margin:0;
}
.blog {
float:left;
}
.conteudo {
width:600px;
margin:25px auto;
padding:25px;
background: #fff;
border:1px solid #dedede;
-webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
-moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
}
.conteudo img {
margin:0 0 25px -25px;
max-width: 650px;
min-width: 650px;
}
.conteudo h1 {
margin:0 0 15px;
padding:0;
font-family: Georgia;
font-weight: normal;
color: #666;
}
.conteudo p:last-child {
margin: 0;
}
.conteudo .continue-lendo {
color:#000;
font-weight: 700;
text-decoration: none;
transition: all 0.5s ease;
}
.conteudo .continue-lendo:hover {
margin-left:10px;
}
.post-info {
float: right;
margin: -10px 0 15px;
font-size: 12px;
text-transform: uppercase;
}
@media screen and (max-width: 960px) {
.header {
position:inherit;
}
.wrap {
width: 90%;
margin:25px auto;
}
.sidebar {
width:100%;
float:right;
margin:25px 0 0;
}
.sidebar .widget {
padding:5%;
}
nav.menu ul {
width: 100%;
}
nav.menu ul {
float:inherit;
}
nav.menu ul li {
float:inherit;
margin:0;
}
nav.menu ul a {
padding:15px;
font-size: 16px;
border-bottom:1px solid #16a085;
border-top:1px solid #1abf9f;
}
.blog {
width:90%;
}
.conteudo {
float:inherit;
width:101%;
padding:5%;
margin:0 auto 25px;
background: #fff;
border:1px solid #dedede;
}
.conteudo img {
margin:0 0 25px -5%;
max-width: 110%;
min-width: 110%;
}
.conteudo .continue-lendo:hover {
margin-left:0;
}
}
@media screen and (max-width: 460px) {
nav.menu ul a {
padding:15px;
font-size: 14px;
}
.sidebar {
display:none
}
.post-info {
display:none;
}
.conteudo {
margin:25px auto;
}
.conteudo img {
margin:-5% 0 25px -5%;
}
}
在views.py编写主页测试代码
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template, url_for
@app.route('/')
def index():
return render_template('welcome.html', title="Welcome")
@app.route('/home')
def home():
return render_template('base.html', title="Home")
打开浏览器, 访问http://127.0.0.1:5000/home, 你会看到精美小清新的主页框架