文本用flask写个博客系统,源码带有详细注释,通俗易懂,拿去就能用。博客效果如下,博客首页:
这个博客麻雀虽小,但五脏俱全。有如下功能:
- 博客文章浏览
- 用户注册
- 用户登录/登出
- 发文章/修改文章/删除文章
为了简单,没有用MySQL数据,使用了Sqlite数据库。博客来自flask官方教程,用来学习前后端开发,基于模板的后端开发,也能够学习python后端框架flask。因为例子够简单,适合初学者入门,当然前提是,你得有python编程基础。好了,项目的源代码已经传到这里了 flaskr,打开连接看readme.md文档,就知道怎么部署这个博客了(部署就是把博客跑起来!)。源代码添加了详细的注释,方便初学的朋友学习食用。
比如flaksr的主文件:
import os
from flask import Flask# 应用工厂函数
def create_app(test_config=None):# 设置配置相对于实例文件夹(instance folder),# flask从实例文件夹读取配置,而不是flask应用的根目录,# __name__是让flask知道自己的位置以设置一些路径,如应用程序的根目录和静态文件目录app = Flask(__name__, instance_relative_config=True)# 设置app默认配置app.config.from_mapping(# 保护flask和扩展(extensions)的数据安全SECRET_KEY='dev',# sqlite文件保存路径DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),)# 加载真正的配置if test_config is None:# config.py文件也存放在实例文件夹中app.config.from_pyfile('config.py', silent=True)else:# 加载测试配置app.config.from_mapping(test_config)# 创建实例文件夹try:os.makedirs(app.instance_path)except OSError:pass# 一个简单的路由@app.route('/hello')def hello():return 'Hello, World!'# 初始化数据库表from . import dbdb.init_app(app)# 注册认证(auth)蓝图from . import authapp.register_blueprint(auth.bp)# 注册博客(写博文、看博文等)蓝图from . import blogapp.register_blueprint(blog.bp)# 添加一条映射关系:/ -> index,# 让url_for('index')返回/,让url_for('blog.index')也返回/(即blog.py的@bp.route('/'))app.add_url_rule('/', endpoint='index')return app# 进入flask_tutorial目录,运行app并开启调试模式:
# flask --app flaskr run --debug# 进入flask_tutorial目录,初始化数据库表:
# flask --app flaskr init-db
还带有pytest测试目录tests
,比如tests/test_auth.py
文件用来测试认证相关的功能:
import pytest
from flask import g, session
from flaskr.db import get_dbdef test_register(client, app):# 测试获取注册页是否符合预期assert client.get('/auth/register').status_code == 200# 测试提交表单给注册页response = client.post(# 用字典形式传递数据,测试客户端会转换为表单数据给视图函数'/auth/register', data={'username': 'a', 'password': 'a'})# 如果注册成功,会跳转到登录页,此时响应头中会有Location字段assert response.headers['Location'] == '/auth/login'with app.app_context():assert get_db().execute('SELECT * FROM user WHERE username="a"',).fetchone() is not None# 使用pytest参数化测试装饰器,
# 第一个参数指定被装饰的test_register_validate_input测试用例会有三个参数,
# 测试用例的client参数是fixture装饰过的函数,它有参数app,app也是被fixture
# 装饰过的函数,因此pytest会依次:调用app->返回值给client->调用client->
# 返回值给test_register_validate_input。
# 第二个参数元组中有三组数据,pytest会分别传递给测试用例,以便把三种情况都测试一遍,
# 利用参数化测试的好处是不用把测试用例test_register_validate_input重复写三遍
@pytest.mark.parametrize(('username', 'password', 'message'), (('', '', b'Username is required.'),('a', '', b'Password is required.'),('test', 'test', b'already registered'),)
)
def test_register_validate_input(client, username, password, message):response = client.post('/auth/register',data={'username': username, 'password': password})# response.data是bytes类型,# 测试注册失败的各种情况,看响应体中是否包含对应的错误提示信息assert message in response.datadef test_login(client, auth):assert client.get('/auth/login').status_code == 200response = auth.login() # 登录 test/test 用户assert response.headers['Location'] == '/'# 在请求之外访问 session 会引发错误,所以使用with上下文with client:client.get('/')assert session['user_id'] == 1assert g.user['username'] == 'test'@pytest.mark.parametrize(('username', 'password', 'message'), (('a', 'test', b'Incorrect username.'),('test', 'a', b'Incorrect password.'),)
)
def test_login_validate_input(auth, username, password, message):response = auth.login(username, password)assert message in response.datadef test_logout(client, auth):auth.login()with client:auth.logout()assert 'user_id' not in session
所有的文件,包括源码文件,测试文件,部署说明都在 这里 了。
部署到云服务器,可以用nginx做web服务器,博客代码跑在wsgi服务器上,比如waitress,或者Gunicorn等等。
nginx配置文件可以这样写,创建一个文件flaskr.conf,内容如下:
server {listen 80 default_server;server_name _;# 把所有http请求永久重定向到httpsrewrite ^/(.*) https://$host/$1 permanent;
}server {listen 443 ssl;server_name fk.izhaojie.com; index index.html;# f这是最关键的部分,让nginx把请求转发给flask后端,由wsgi服务处理location / {proxy_pass http://127.0.0.1:8080;}
}
完!