1. 开发工具
不管Windows还是Linux都可以使用PyCharm作为IDE,功能齐全,使用方便。
2. 创建VirtualEvn
如果使用PyCharm就不用再在命令行创建ve了,直接新建工程,并选择create virtualevn,命名并选择保存路径即可。
3. 安装包依赖包
在PyCharm中通过菜单[File]->[Settings]->[Project:youprojectname]->[Project Interpreter],可查看该环境下已安装的包,并点击“+”图标可以添加新包,也可以在此删除包。根据一般Flask工程需求,我们需要安装的包有:
安装这些包的时候可能会附带安装其依赖包。
- Flask(包含了Werkzeug和Jinja2)
- Flask-SQLAlchemy
- Flask-MySQLdb
- Flask-Migrate
- Flask-script
4. 工程目录结构
一个典型的工程目录结构如下:
+program //项目目录
+app //应用程序目录
+view1 //应用模块1
-__init__.py //蓝图定义,过滤器定义,上下文函数变量定义
-view.py //应用模块1的具体处理函数
+view2 //应用模块2
+models //数据模型
-model1.py //定义具体的数据模型类
+static //静态文件(css,js,images等)
+templates //模板目录,存放页面模板,可用子目录区分不同应用的模板文件
-__init__.py //定义SQLAlchemy的实例,并定义create_app函数用于创建Flask应用及相关初始化
+log //日志文件夹
+venv //环境目录
+migrations //数据迁移,自动生成的,不需管理
-config.py //系统配置文件(数据库,密钥等)
-manage.py //管理数据迁移
-run.py //启动app
5. config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
DEBUG = False
TESTING = False
SECRET_KEY = os.environ.get('SECRET_KEY') or \
b'\x90\x87d\xcfk\xbd\x81\xa2\\G\xb2\x9a\x8d\xe5\xb5c\xa3\xbd\x85\x8c\x8c\x86\xbc`\x94ZM\xf5\xdaN\x92'
SQLALCHEMY_COMMIT_ON_TEARDOWN = True
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:database/flaskdb.db'
SQLALCHEMY_TRACK_MODIFICATIONS = True
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:database/flaskdb.db'
SQLALCHEMY_TRACK_MODIFICATIONS = True
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'mysql://user:password&lp@localhost:3306/flaskdb'
SQLALCHEMY_TRACK_MODIFICATIONS = True
config = {
'development':DevelopmentConfig,
'testing':TestingConfig,
'production':ProductionConfig,
'default':DevelopmentConfig,
}
6. app/__init__.py
from flask import Flask, render_template, logging
from flask_sqlalchemy import SQLAlchemy
from logging.handlers import TimedRotatingFileHandler
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
#添加日志处理
mylog = TimedRotatingFileHandler('log/mylog.log', 'D')
mylog.setLevel(logging.DEBUG)
mylog.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
app.logger.addHandler(mylog)
#初始化DB
db.init_app(app)
#注册蓝本
from app.view1 import view1 as view1_blueprint
app.register_blueprint(view1_blueprint, url_prefix='/view1')
#附加路由,自定义错误页面
return app
7. run.py
import os
from app import create_app
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
if __name__ == '__main__':
app.run()
8. manage.py
import os
from app import create_app, db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
'''
manager使用说明:
命令格式:python3 manager.py db [command]
在PyCharm中可对manager.py编辑参数 db [command]
command说明:
init-初始化数据库迁移(自动生成migrations目录及文件),仅在第一次使用
migrate-生成迁移数据,自动根据model变化生成迁移数据文件,含版本控制
upgrade-执行升级操作,将变动的表结构提交到数据库,保留数据库原数据
downgrade-执行降级操作, 相当于撤回本次升级操作
'''
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
manager.run()
9. model1.py
from app import db
class Book(db.Model):
__tablename__ = 'book'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True)
pub_date = db.Column(db.DateTime)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Book %r>" % self.name
10. app/view1/__init__.py
from flask import Blueprint
#蓝本定义
view1 = Blueprint('view1', __name__)
from app.view1 import view
#自定义过滤器
@book.app_template_filter('reverse')
def reverse_filter(s):
return s[::-1]
#自定义上下文过程,可返回一个字典,包含模板可用的变量和函数
@book.context_processor
def utility_processor():
rt = dict()
def format_date(date):
return date.strftime('%Y{y}%m{m}%d{d}').format(y='年', m='月', d='日')
rt['formatdate'] = format_date
def format_date2(date):
return date.strftime('%Y-%m-%d')
rt['formatdate2'] = format_date2
rt['xname'] = 'other strings'
return rt
11. app/view1/view.py
from flask import render_template, flash, current_app
from app.models.model1 import Book
from . import view1
@view1.route('/', methods=['GET'])
def index():
books = Book.query.all()
return render_template('book/bookindex.html', books=books)
@view1.route('/index2', method=['GET', 'POST'])
def index2():
books = Book.query.all()
return render_template('book/bookindex2.html', books=books)
12. app/templates/book/bookindex.html,layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>详细页面</title>
<link rel="stylesheet" href="/static/main.css"/>
</head>
<body>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul>
{% for category, message in messages %}
<li class="{{ category }}">{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}{% endblock %}
</body>
</html>
bookindex.html
{% extends "book/layout.html" %}
{% block body %}
<h1><a href="{{url_for('index')}}">首页</a> </h1>
{%for book in books%}
<li>{{ book.name | reverse }}==={{ formatdate(book.pub_date) }}</li>
{%endfor%}
{% endblock %}