基于Flask框架的任务管理系统

基于Flask框架的任务管理系统

基本功能:

  • 任务的添加、删除、查看、编辑、点击完成
  • 用户登录、登出

##数据库层
任务:

  • 任务id号
  • 任务名
  • 任务添加时间
  • 任务的状态(完成/未完成)
  • 任务所属部门(外键关联部门department.id)

部门

  • 部门id编号
  • 部门名称
  • 部门任务(关联Todo)
  • 部门用户(关联User)

用户

  • 用户id编号
  • 用户名
  • 用户密码
  • 邮箱地址
  • 联系方式
  • 用户简介
  • 注册时间
  • 所属部门
  • 用户操作日志

用户登录日志

  • 日志编号
  • 用户(关联user)
  • 登录主机ip
  • 登录时间
  • 登录地区
    models.py
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'
        }
    )

##视图函数层

基本内容:

  • 首页
  • 用户登录
  • 用户退出
  • 任务列表
  • 任务添加
  • 任务删除
  • 任务编辑
    views.py
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 %}
    

{% for todo in todos.items %} {% endfor %}

任务列表

任务编号 任务名称 创建时间 所属部门 任务状态 操作
{{ todo.id }} {{ todo.name }} {{ todo.add_time }} {{ todo.department.name }} {% if todo.status %} 已完成 {% else %} 未完成 {% endif %} 删除 编辑
{% from 'macro/page.html' import paginate %} {{ paginate('list',todos) }}
{% 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 %}

你可能感兴趣的:(Flask)