基本功能:
##数据库层
任务:
部门
用户
用户登录日志
import os
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
#将models绑定app
app=Flask(__name__)
#配置ORM
app.config['SQLALCHEMY_DATABASE_URI']='mysql+pymysql://root:@localhost/TodoProject'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True
#CSRF加密密钥验证,字符变量由24个随机字符组成
app.config['SECRET_KEY']=os.urandom(24)
#绑定Bootstrap前端框架,可以使用框架内简洁的样式
Bootstrap(app)
#实例化db对象
db=SQLAlchemy(app)
class Todo(db.Model):
"""一个关于任务的类"""
id=db.Column(db.Integer,autoincrement=True,primary_key=True) #任务编号
name=db.Column(db.String(50),unique=True) #任务名称
add_time=db.Column(db.DateTime,default=datetime.now()) #创建任务的时间
status=db.Column(db.Boolean,default=False) #任务的状态
#外键关联部门的id
department_id=db.Column(db.Integer,db.ForeignKey('department.id'))
class Department(db.Model):
"""一个关于部门的类"""
id=db.Column(db.Integer,autoincrement=True,primary_key=True) #任务编号
name=db.Column(db.String(50),unique=True)
todos=db.relationship('Todo',backref='department')
users=db.relationship('User',backref='department')
class User(db.Model):
"""一个关于用户的类"""
id=db.Column(db.Integer,autoincrement=True,primary_key=True) #任务编号
name=db.Column(db.String(20),unique=True)
pwd=db.Column(db.String(100))
email=db.Column(db.String(50),unique=True)
phone=db.Column(db.String(20),unique=True)
info=db.Column(db.Text)
add_time=db.Column(db.DateTime,default=datetime.now())
department_id=db.Column(db.Integer,db.ForeignKey('department.id'))
userlog=db.relationship('Userlog',backref='user')
class Userlog(db.Model):
"""一个关于用户登录日志的类"""
id=db.Column(db.Integer,autoincrement=True,primary_key=True) #任务编号
user_id=db.Column(db.Integer,db.ForeignKey('user.id'))
ip=db.Column(db.String(100))
add_time=db.Column(db.DateTime,default=datetime.now())
areas=db.Column(db.String(100))
if __name__=='__main__':
#创建数据库表
db.create_all()
##form表单
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField,PasswordField
from wtforms.validators import DataRequired,Length
class LoginForm(FlaskForm):
name=StringField(
label="用户名",
validators=[
DataRequired("请输入用户名"),
Length(6,10)
],
render_kw={
'placeholder':"请输入用户名"
}
)
passwd=PasswordField(
label="用户密码",
validators=[
DataRequired("请输入用户密码"),
Length(6,10)
],
render_kw={
'placeholder':"请输入用户密码"
}
)
submit=SubmitField(
render_kw={
'value':'登陆',
'class':'btn btn-success pull-right'
}
)
#任务编辑
class EditForm(FlaskForm):
name=StringField(
label='任务名称',
validators=[
DataRequired()
]
)
department=StringField(
label="所属部门",
validators=[
DataRequired()
]
)
submit=SubmitField(
render_kw={
'value':'完成',
'class':'btn btn-success pull-right'
}
)
##视图函数层
基本内容:
import json
import time
from functools import wraps
from urllib.request import urlopen
from models import app, Userlog, User, Todo, Department, db
from flask import render_template, redirect, request, url_for, flash, session
from forms import LoginForm,EditForm
from werkzeug.security import check_password_hash,generate_password_hash
#首页
@app.route('/')
def headpage():
return render_template('base.html')
#获取用户登陆主机ip的所在地
def get_ip_area(ip):
url='http://ip.taobao.com/service/getIpInfo.php?ip=%s' %(ip)
json_data=urlopen(url).read().decode('utf-8')
s_data=json.loads(json_data)
country=s_data['data']['country']
if country=='xx':
country==''
city=s_data['data']['city']
if city=='xx':
city==''
return country+city
#判断用户是否登陆,检测会话中有无用户信息
def islogin(f):
@wraps(f)
def wrapper(*args,**kwargs):
if not 'user' in session:
return redirect(url_for('login'))
return f(*args,**kwargs)
return wrapper
#登陆页面
@app.route('/login/',methods=['POST','GET'])
def login():
forms=LoginForm()
if request.method=='POST':
u=User.query.filter_by(name=forms.name.data).first()
pwd=forms.passwd.data
if u and check_password_hash(u.pwd,pwd):
session['user']=u.name
session['user_id']=u.id
userlog=Userlog(
user_id=u.id,
ip=request.remote_addr,
areas=get_ip_area(request.remote_addr)
)
db.session.add(userlog)
db.session.commit()
flash('登陆成功','ok')
time.sleep(2)
return redirect('/list/')
else:
flash('用户名或密码错误','error')
return render_template('login.html',forms=forms)
#任务列表
@app.route('/list/',methods=['GET','POST'])
@app.route('/list/')
@islogin
def list(page=1):
todos = Todo.query.paginate(page,per_page=4)
parts = Department.query.all()
return render_template('list.html',todos=todos,parts=parts)
#点击完成
@app.route('/todoup//')
@app.route('/todoup/')
@islogin
def todoup(page,id):
todo=Todo.query.filter_by(id=id).first()
todo.status=1
db.session.add(todo)
db.session.commit()
return redirect(url_for('list',page=page))
#点击未完成
@app.route('/tododown//')
@app.route('/tododown/')
@islogin
def tododown(page,id):
todo=Todo.query.filter_by(id=id).first()
todo.status=0
db.session.add(todo)
db.session.commit()
return redirect(url_for('list',page=page))
#删除操作
@app.route('/delete//')
@islogin
def delete(page,id):
todo=Todo.query.filter_by(id=id).first()
db.session.delete(todo)
db.session.commit()
return redirect(url_for('list',page=page))
#编辑操作
@app.route('/edit//',methods=['GET','POST'])
@islogin
def edit(page,id):
forms=EditForm()
todo = Todo.query.filter_by(id=id).first()
oldname = todo.name
oldpart=todo.department_id
if request.method == 'POST':
todo.name=forms.name.data
todo.department_id=forms.department.data
db.session.add(todo)
db.session.commit()
return redirect(url_for('list', page=page))
forms.name.data=oldname
forms.department.data=oldpart
return render_template('edit.html',forms=forms)
#添加任务
@app.route('/add/',methods=['POST'])
@islogin
def add():
todoname=request.form['name']
part=request.form['part']
todo=Todo(name=todoname,department_id=part)
db.session.add(todo)
db.session.commit()
return redirect(url_for('list'))
#用户注销
@app.route('/logout/')
@islogin
def logout():
session.pop('user',None)
session.pop('user_id',None)
return redirect(url_for('login'))
#用户注销
@app.route('/backhead/')
@islogin
def backhead():
session.pop('user',None)
session.pop('user_id',None)
return redirect(url_for('headpage'))
app.run(port='9000')
##模板层
templates
├── base.html #基础模版:导航栏
├── edit.html #编辑任务模版(继承base.html)
├── list.html #任务列表模版(继承base.html)
├── login.html #用户登录模版(继承base.html)
└── macro #自定义的宏,用于分页列表的操作
└── page.html
base.html
{% extends 'bootstrap/base.html' %}
{% block titie %}
首页
{% endblock %}
{% block navbar %}
{% endblock %}
{% block content %}
{% endblock %}
login.html
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block titie %}
用户登录
{% endblock %}
{% block content %}
用户登录
{% for msg in get_flashed_messages(category_filter='ok') %}
{{ msg }}
{% endfor %}
{% for msg in get_flashed_messages(category_filter='error') %}
{{ msg }}
{% endfor %}
{{ wtf.quick_form(forms) }}
{% endblock %}
list.html
{% extends 'base.html' %}
{% block titie %}
处理任务
{% endblock %}
{% block navbar %}
{% endblock %}
{% block content %}
{% endblock %}
macro/page.html
{% macro paginate(funame,dataObj) %}
{# 点击前一页 #}
-
{% if dataObj.has_prev %}
- «
{% else %}
- «
{% endif %}
{# 点击首页#}
- 首页
-
{# 中间页列表,如果页数太多无法显示,则用...代替#}
{% for v in dataObj.iter_pages() %}
{% if v==dataObj.page %}
- {{ v }}
{% elif v==None %}
- ...
{% else %}
- {{ v }}
{% endif %}
{% endfor %}
{# 点击尾页#}
{# - 首页
#}
-
{# 点击下一页 #}
{% if dataObj.has_prev %}
- »
{% else %}
- »
{% endif %}
{% endmacro %}
edit.html
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block titie %}
编辑任务
{% endblock %}
{% block content %}
编辑任务
{% for msg in get_flashed_messages(category_filter='ok') %}
{{ msg }}
{% endfor %}
{% for msg in get_flashed_messages(category_filter='error') %}
{{ msg }}
{% endfor %}
{{ wtf.quick_form(forms) }}
{% endblock %}