基于Flask与Bootstrap的Python任务管理清单实现

Mason
Mason
发布时间:2026-10-13 | 4人浏览过
原创

本文详细介绍如何使用Python Flask框架结合Bootstrap前端库,构建一个轻量级的任务管理清单系统。通过展示base.html、list.html、models.py、views.py及run.py等核心文件代码,演示了从数据库模型定义、路由逻辑处理到前端页面渲染的完整流程,为初学者提供可直接参考的实战案例。

基础模板与页面结构定义

首先定义基础HTML模板文件base.html,该文件作为整个项目的父模板,负责统一导航栏、样式引入及页脚信息。代码中通过{% extends "bootstrap/base.html" %}继承Bootstrap基础模板,并在{% block styles %}中引入自定义CSS样式../static/css/main.css。导航栏部分使用Bootstrap的navbar组件,包含移动端折叠按钮、品牌标识及用户登录状态判断逻辑。内容区域通过{% block newcontent %}预留插槽,供子页面填充具体业务内容,最后通过{% block footer %}添加版权信息及ICP备案号。


{% extends "bootstrap/base.html" %}

{% block styles %}
  {{ super() }}
  <link rel="stylesheet" href="../static/css/main.css" rel="external nofollow" >
{% endblock %}

{% block navbar %}
  <nav class="navbar navbar-default">
    <div class="container-fluid">
      <!-- Brand and toggle get grouped for better mobile display -->
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
            data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="index.html" rel="external nofollow" ></a>
      </div>

      <!-- Collect the nav links, forms, and other content for toggling -->
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
        <ul class="nav navbar-nav">
           <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ></a></li>
           <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" ></a></li>
          <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >首页<span class="sr-only">(current)</span></a></li>
          <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >新闻</a></li>
          <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >国际</a></li>
          <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >国内</a></li>
          <li><a href="/sysinfo/" rel="external nofollow" >系统信息</a></li>
          <li><a href="#" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" >登陆用户</a></li>
        </ul>
        <ul class="nav navbar-nav navbar-right">

          {% if 'user' in session %}
            <li><a href="login.html" rel="external nofollow" ><span class="glyphicon glyphicon-user"></span>
              &nbsp;&nbsp; {{ session.user }}</a></li>
            <li><a href="/logout/" rel="external nofollow" ><span class="glyphicon glyphicon-log-in"></span>
              &nbsp;&nbsp; 注销 </a></li>

          {% else %}

            <li><a href="/login/" rel="external nofollow" ><span class="glyphicon glyphicon-log-in"></span>
              &nbsp;&nbsp;登陆</a></li>
            <li><a href="/register/" rel="external nofollow" ><span class="glyphicon glyphicon-log-out"></span>
            &nbsp;&nbsp;注册</a></li>
          {% endif %}



        </ul>
      </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
  </nav>
{% endblock %}

{% block content %}
  {#定义属于自己的block#}
  {% block newcontent %}

  {% endblock %}

  {% block footer %}

    <div class="footer">


      京ICP备11008151号京公网安备11010802014853

    </div>

  {% endblock %}
{% endblock %}

任务列表与添加功能实现

接着实现任务列表页面list.html,该页面继承自base.html,主要用于展示任务添加表单及现有任务列表。在{% block newcontent %}中,首先构建一个水平表单用于添加新任务,包含文本输入框(name="todo_name")用于输入任务名称,下拉选择框(name="part")用于选择任务所属部门,以及提交按钮。随后,通过遍历parts列表渲染部门选项,利用{% for todo in todos %}循环遍历所有任务,展示任务名称、所属部门,并提供“完成”和“删除”操作链接,其中删除链接指向/todo/delete/{{ todo.id }}/接口。


{% extends 'base.html' %}

{% block newcontent %}
  <div class="row">
    <div class="col-md-6 col-md-offset-3">
      /*添加任务*/
      <form class="form-horizontal" action="/todo/add/" method="post">
        <div class="form-group">
          {# 添加框          #}
          <div class="col-sm-9">
            <input type="text" class="form-control" placeholder="请添加任务" required="required"
                name="todo_name">
          </div>
          {#  选择框       #}
          <div class="col-sm-2">
            <select class="form-control" name="part">
              {% for part in parts %}
                <option value="{{ part.id }}">{{ part.name }}</option>
              {% endfor %}
            </select>
          </div>

          {#  添加的按钮       #}
          <div class="col-sm-1">
            <input type="submit" class="btn btn-success" value="添加任务">
          </div>
        </div>

      </form>

      /*任务显示*/
      <h1>添加任务</h1>
      <table class="table table-bordered">
        <tr>
          <td>任务内容</td>
          <td>创建时间</td>
          <td>状态</td>
          <td>所属部门</td>
          <td>操作</td>
        </tr>
        {% for todo in todos %}
          <tr>
            <td>{{ todo.name }}</td>
            <td>{{ todo.add_time }}</td>
            {#    #}
            <td>
              {% if todo.status %}
                 <a href="/todo/undo/{{ todo.id }}/" rel="external nofollow" class="btn btn-sm btn-success" role="button"><span
              class="glyphicon glyphicon-ok"></span> 已完成</a>

              {% else %}
                <a href="/todo/done/{{ todo.id }}/" rel="external nofollow" class="btn btn-sm btn-warning" role="button"><span
              class="glyphicon glyphicon-remove"></span> 未完成</a>

              {% endif %}

            </td>
            <td>{{ todo.department.name }}</td>
            <td><a href="/todo/delete/{{ todo.id }}/" rel="external nofollow" class="btn btn-sm btn-danger" role="button"><span
              class="glyphicon glyphicon-remove"></span> 删除</a></td>
          </tr>

        {% endfor %}


      </table>
    </div>
  </div>

{% endblock %}

数据库模型与关系设计

然后定义数据模型models.py,使用Flask-SQLAlchemy进行数据库交互。配置数据库连接为mysql+pymysql://root:971203@localhost/Todo,并开启SQLAlchemy对象修改追踪。定义了User(用户)、Department(部门)、Todo(任务)和Userlog(登录日志)四个核心模型。User模型包含id、name(唯一且非空)、pwd、email和phone字段;Department模型包含id和name字段;Todo模型包含id、name、status(状态)、add_time(创建时间)和department_id(外键关联部门);Userlog模型记录登录日志,包含id、add_time、ip、area和user_id(外键关联用户)。各模型间通过db.ForeignKey建立一对多关系,如User与Todo、User与Userlog。


from datetime import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bootstrap import Bootstrap

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:971203@localhost/Todo'
# SQLAlchemy 将会追踪对象的修改并且发送信号。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
bootstrap = Bootstrap(app)
app.config['SECRET_KEY'] = 'westos'
# 1). 面向对象方式创建表
# 2). 分析关系:
#    部门和用户: 一对多
#    用户和任务: 一对多的关系
#    用户和用户登录日志: 一对多的关系
# 实现一对多(Role(1): User(n))的关系
#  - 多的一端写外键
#  - 少的一端写反向引用

class User(db.Model):
  id = db.Column(db.Integer, autoincrement=True, primary_key=True)
  # unique:用户名唯一, nullable=False指用户名不能为空;
  name = db.Column(db.String(50), unique=True, nullable=False)
  pwd = db.Column(db.String(100))
  email = db.Column(db.String(30), unique=True)
  phone = db.Column(db.String(30), 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'))
  todos = db.relationship('Todo', backref='user')
  userlogs = db.relationship('Userlog', backref='user')
  # 部门id与其他表关联,不能随便写

  def __repr__(self):
    return '<User: %s>' %(self.name)


# 部门
class Department(db.Model):
  id = db.Column(db.Integer, autoincrement=True, primary_key=True)
  name = db.Column(db.String(50), unique=True, nullable=False)
  # 反向引用: user就包含一个属性, department
  users = db.relationship('User', backref='department')
  todos = db.relationship('Todo', backref='department')
  def __repr__(self):
    return '<Department: %s>' %(self.name)

class Todo(db.Model):
  id = db.Column(db.Integer, autoincrement=True, primary_key=True)
  name = db.Column(db.String(200), nullable=False)
  add_time = db.Column(db.DateTime, default=datetime.now()) # 创建时间
  status = db.Column(db.Boolean, default=False) # 任务状态, 默认为Flase(未完成)
  department_id = db.Column(db.Integer, db.ForeignKey('department.id'))
  user_id = db.Column(db.Integer,db.ForeignKey('user.id') )

  def __repr__(self):
    return '<Todo: %s>' % (self.id)

# 用户登录日志
class Userlog(db.Model):
  id = db.Column(db.Integer, autoincrement=True, primary_key=True)
  add_time = db.Column(db.DateTime, default=datetime.now()) # 创建时间
  ip = db.Column(db.String(200), nullable=False) # 登录ip
  area = db.Column(db.String(200)) # 用户登录地点
  user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # 外键


  def __repr__(self):
    return '<Userlog: %s>' % (self.ip)

视图逻辑与路由处理

随后编写视图逻辑views.py,处理HTTP请求与页面渲染。导入Flask相关组件及models中的app、db及各模型。定义index路由渲染base.html。register路由处理用户注册,通过RegisterForm验证表单数据。login路由处理用户登录,使用LoginForm获取用户输入,验证用户名和密码后,若成功则记录登录日志(ip、area等)并跳转至首页。todo_list路由负责渲染任务列表页面,传递todos和parts数据。此外,定义add、delete、undo、done等路由,分别处理任务的添加、删除、标记未完成和标记完成操作,操作完成后重定向回todo_list页面。


from flask import render_template, request, redirect, url_for, session

from models import app, Todo, db, Department,User
from mDB import isPasswdOk,isUserExist,addUser
from forms import LoginForm,RegisterForm
@app.route('/')
def index():
  return render_template('base.html')
@app.route('/register/')
def register():
  form = RegisterForm()
  if form.validate_on_submit():
    user = request.form('user')
    passwd = request.form('passwd')
  return render_template('register.html')

@app.route('/login/',methods=['GET','POST'])
def login():
  form = LoginForm()
  # 如果是post方法并且表单验证通过的话, 返回True;
  if form.validate_on_submit():
    # 1). 获取用户提交的表单信息
    # print(form.data) 是字典类型, 内容如下:
    # {'user': 'westos', 'passwd': 'westos', 'submit': True }
    user = form.data['user']
    passwd = form.data['passwd']
    # 2. 判断用户名和密码是否正确

    if isPasswdOk(user, passwd):
      # 将用户名和密码信息存储到session中;
      session['user'] = user
      session['passwd'] = passwd
      # 如果登陆成功, 跳转到主页;
      return redirect(url_for('todo_list'))
    else:
      # 如果登陆失败, 重新登陆;
      return render_template('login.html',form=form, message="用户名或者密码错误")
  return render_template('login.html', form=form)
@app.route('/logout/')
def logout():
  session.pop('user',None)
  session.pop('passwd',None)
  return redirect(url_for('todo_list'))
# 任务的增删改查
@app.route('/todo/add/', methods=['POST'])
def todo_add():
  # 获取提交的任务信息
  name = request.form['todo_name']
  part = request.form['part']
  # 添加完成之后, 返回任务列表显示页面
  u = User.query.filter_by(name=session['user']).first()
  id = u.id
  todo = Todo(name=name, department_id=part, user_id=id)
  db.session.add(todo)
  db.session.commit()

  return redirect(url_for('todo_list'))

@app.route('/todo/delete/<int:id>/')
def todo_delete(id):
  u = Todo.query.filter_by(id=id).first()
  db.session.delete(u)
  db.session.commit()
  return redirect(url_for('todo_list'))

@app.route('/list/')
def todo_list():
  # 1). 从数据库中查询
  todos = Todo.query.all()
  parts = Department.query.all()

  return render_template('list.html',
              todos = todos,
              parts=parts)

# 修改任务的状态(变成已完成状态/变成未完成状态)
@app.route('/todo/undo/<int:id>/')
def undo(id):
  todo = Todo.query.filter_by(id=id).first()
  todo.status = False
  db.session.commit()
  # 更新状态后, 返回任务列表页
  return redirect(url_for('todo_list'))

@app.route('/todo/done/<int:id>/')
def done(id):
  todo = Todo.query.filter_by(id=id).first()
  todo.status = True
  db.session.commit()
  # 更新状态后, 返回任务列表页
  return redirect(url_for('todo_list'))

项目启动脚本配置

最后,创建项目运行脚本run.py,作为程序入口。该文件导入models中的app和db,以及views中定义的所有路由函数。通过调用app.run()启动Flask开发服务器,使任务管理清单系统可在本地运行并接受HTTP请求。


# 项目真实运行脚本

from models import app,db
# 导入编写的视图函数和路由
from views import *

app.run()

以上代码展示了使用Python Flask和Bootstrap构建任务管理系统的完整流程,涵盖模板继承、数据库建模、路由处理及前端交互。该案例结构清晰,代码规范,适合Web开发初学者参考学习,帮助快速掌握Flask框架的核心用法及前后端交互原理。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表