1.目标
本项目将学习 Mariadb 作为数据库后端,Bootstrap 作为前端的技术栈,并实现一个清单应用。从中我们可以学习 Flask Web 应用框架,及 Mariadb 关系型数据库和 BootStrap web开发框架。
2.项目介绍
本应用修改自 TodoMVC 的 todo list 应用,使用 Mariadb 作为数据库后端,Bootstrap 作为前端的 Flask 应用。先给它起个好听的名字吧,方便之后称呼。
todo list => (自定义,随便起名称) => todoest
就像一般的 todo list 应用一样,todoest 实现了以下功能:
- 管理数据库连接
- 列出所有的 todo 项
- 创建新的 todo
- 检索单个 todo
- 编辑单个 todo 或将其标记为已完成
- 删除单个 todo
3.项目效果
- 新建标签页,启动 todoest
- 打开浏览器访问 http://localhost:8000/
4.技术分析
-
为什么选择Flask?
Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 。Flask使用 BSD 授权。
Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
因此Flask是一个使用Python编写的轻量级Web应用框架。轻巧易扩展,而且够主流,有问题不怕找不到人问,最适合 todoest 这种轻应用了。 -
为什么选择Mariadb?
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。MariaDB虽然被视为MySQL数据库的替代品,但它在扩展功能、存储引擎以及一些新的功能改进方面都强过MySQL。而且从MySQL迁移到MariaDB也是非常简单的.
-
为什么选择Bootstrap?
Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。
Bootstrap中包含了丰富的Web组件,根据这些组件,可以快速的搭建一个漂亮、功能完备的网站。其中包括以下组件:下拉菜单、按钮组、按钮下拉菜单、导航、导航条、路径导航、分页、排版、缩略图、警告对话框、进度条、媒体对象等
5.设计结构
1.架构
首先在mysql里新建数据库
create database Todo DEFAULT CHARSET utf8
SQLALCHEMY_DATABASE_URI = 'mysql://root:redhat@localhost/Todo'
SQLALCHEMY_TRACK_MODIFICATIONS = True
from app import manager
if __name__ == '__main__':
manager.run()
init.py
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
import pymysql
pymysql.install_as_MySQLdb()
app = Flask(__name__)
app.config.from_pyfile('../config.py')
db = SQLAlchemy(app)
manager = Manager(app)
models.py
数据库:
存储三类 用户/Todo/Todo的类型
"""
# 存储数据库相关的操作
"""
from app import db
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
# 用户和任务的关系: 一对多, 用户是一, 任务是多,
# 用户和分类的关系:
class User(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
username = db.Column(db.String(20), unique=True)
password_hash = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(30), unique=True)
add_time = db.Column(db.DateTime, default=datetime.now()) # 账户创建时间
# 1). User添加属性todos; 2). Todo添加属性user;
todos = db.relationship('Todo', backref="user")
categories = db.relationship('Category', backref='user')
@property
def password(self):
"""u.password"""
raise AttributeError("密码属性不可以读取")
@password.setter
def password(self, password):
"""u.password = xxxxx """
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
"""验证密码是否正确"""
return check_password_hash(self.password_hash, password)
def __repr__(self):
return "<User %s>" %(self.username)
# 任务和分类的关系: 一对多
# 分类是一, 任务是多, 外键写在多的一端
class Todo(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
content = db.Column(db.String(100)) # 任务内容
status = db.Column(db.Boolean, default=False) # 任务的状态
add_time = db.Column(db.DateTime, default=datetime.now()) # 任务创建时间
# 任务的类型,关联另外一个表的id
category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
# 任务所属用户;
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return "<Todo %s>" %(self.content[:6])
class Category(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(20), unique=True)
add_time = db.Column(db.DateTime, default=datetime.now()) # 任务创建时间
# 1). Category添加一个属性todos, 2). Todo添加属性category;
todos = db.relationship('Todo', backref='category')
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return "<Category %s>" %(self.name)
# 初始化,用于测试数据库,实际代码不用写,因为把初始化数据库写在models.py文件中更为方便
def init():
db.drop_all()
db.create_all()
u = User(username='admin',email='admin@qq.com')
u.password='admin'
db.session.add(u)
db.session.commit()
print('用户%s创建成功' %(u.username))
c = Category(name='学习',user_id=1)
db.session.add(c)
print('分类%s创建成功' %(c.name))
t = Todo(content='学习flask',category_id=1,user_id=1)
db.session.add(t)
print('任务%s添加成功' %(t.content))
db.session.commit()
if __name__ == '__main__':
init()
view.py–视图函数(先实现登陆注册页面,再写出todo页面框架)
from app import app, db
# 网站首页
from app.forms import RegisterForm, LoginForm
from flask import render_template, flash, redirect, url_for, session
from app.models import User
@app.route('/')
def index():
return 'index'
# 注册页面
@app.route('/register/', methods=['POST', 'GET'])
def register():
form = RegisterForm()
if form.validate_on_submit():
# 1. 从前端获取用户输入的值;
email = form.email.data
username = form.username.data
password = form.password.data
# 2. 判断用户是否已经存在? 如果返回位None,说明可以注册;
u = User.query.filter_by(username=username).first()
if u:
flash("用户%s已经存在" % (u.username))
return redirect(url_for('register'))
else:
u = User(username=username, email=email)
u.password = password
db.session.add(u)
db.session.commit()
flash("注册用户%s成功" % (u.username))
return redirect(url_for('login'))
return render_template('register.html',
form=form)
# 登录页面
@app.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
username = form.username.data
password = form.pass