一、数据库模型
- 用户信息修改
- 添加任务清单
- 添加任务分类
app/models.py
class User(UserMixin, db.Model):
"""用户"""
# .......
# 1). Category添加一个属性todos, 2). Todo添加属性category;
todos = db.relationship('Todo', backref='user')
# ........
class Todo(db.Model):
__tablename__='todos'
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.utcnow) # 任务创建时间
# 任务的类型,关联分类表的id,因为分类:任务=1:N,外键写在多的一端
category_id=db.Column(db.Integer,db.ForeignKey('categories.id'))
# 任务所属用户,用户:任务=1:N,因此外键写在任务一端,关联的是用户表的id
user_id=db.Column(db.Integer,db.ForeignKey('users.id'))
def __repr__(self):
return '<Todo %s>'%(self.content[:6])
class Category(db.Model):
__tablename__='categories'
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.utcnow) # 任务创建时间
# 用户:分类=1:N
user_id=db.Column(db.Integer,db.ForeignKey('users.id'))
# 反向引用:1)Category添加todos属性 2)Todo添加categories属性
todos=db.relationship('Todo',backref='category')
def __repr__(self):
return '<Category %s>'%(self.name)
二、表单文件
- 添加任务的表单
- 编辑任务的表单
- 添加分类的表单
app/todo/forms.py
from flask_wtf import FlaskForm
from wtforms import StringField,SelectField,SubmitField
from wtforms.validators import DataRequired
from app.models import Category
class AddTodoForm(FlaskForm):
content=StringField(
label='任务内容',
validators=[DataRequired()],
render_kw={
'class':'form-control',
'placeholder':'添加任务信息'
}
# 当使用宏时,租用类名为form-control的模板,在list.html中
)
# 下拉表
category=SelectField(
label='任务类型',
coerce=int ,
# choice=[(item.id,item.name) for item in Category.query.all()]
render_kw={
'class':'btn btn-choice dropdown-toggle',
'type': "button",
'data-toggle': "dropdown",
'aria-haspopup': "true",
'aria-expanded': "false"
}
)
submit=SubmitField(
label='添加任务',
render_kw={
'class':'btn btn-default btn-todo-add'
}
)
# 构造方法在实例化对象时自动执行,这里在每次实例化表单对象时,都会重新查询所有的分类,并展示在下拉表中
def __init__(self):
# 执行父类的构造方法
super(AddTodoForm, self).__init__()
categories=Category.query.all()
if categories:
self.category.choices=[(item.id,item.name) for item in categories]
else:
self.category.choices=[(-1,'请先创建分类')]
class EditTodoForm(FlaskForm):
content=StringField(
label='任务内容',
validators=[DataRequired()]
)
category=SelectField(
label='任务类型',
coerce=int,
)
submit=SubmitField(
label='编辑任务',
)
def __init__(self):
super(EditTodoForm, self).__init__()
categories=Category.query.all()
if categories:
self.category.choices=[(item.id,item.name) for item in categories]
else:
self.category.choices=[-1,'请先创建分类']
class AddCategoryForm(FlaskForm):
content = StringField(
label='分类名称',
validators=[DataRequired()]
)
submit = SubmitField(
label='添加分类',
)
三、视图函数文件
app/todo/views.py
# 查看任务
@todo.route('/list/')
@login_required
def list():
form = AddTodoForm() # 添加任务之前首先有一个表单,这里实例化了在forms文件中的表单类
# 任务显示需要分页,每个用户只能查看自己的任务
page=int(request.args.get('page',1)) # request获取用户传入的参数,由于页数是整型,所以int()
todoPageobj=Todo.query.filter_by(
user_id=current_user.id).paginate(
# 在config.py文件中设置PER_PAGE=5
# paginate设置分页,page表示显示几页,per_page表示显示多少条数据
page,per_page=current_app.config['PER_PAGE']
)
return render_template('todo/list.html',todoObj=todoPageobj,form=form)
@todo.route('/add',methods=['POST'])
# 用get方法获取表单页面,post方法提交一些用户输入的新的数据
@login_required
def add():
form = AddTodoForm() # 添加任务之前首先有一个表单,这里实例化了在forms文件中的表单类
if form.validate_on_submit():
# 获取用户提交的内容
content=form.content.data
# 这里虽然填入的是字符串,但是实际存入的是任务id,是由于forms文件中coerce=int的设置
category_id=form.category.data
# 添加到数据库中
todo=Todo(
content=content,
category_id=category_id,
user_id=current_user.id
)
db.session.add(todo)
db.session.commit()
# 闪现信息没有显示,需要在add.html中include一下
flash('添加任务成功',category='success')
return redirect(url_for('todo.list'))
print(Category.query.all())
@todo.route('/edit/<int:id>/',methods=['GET','POST'])
def edit(id):
form=EditTodoForm()
# ****重要**** 编辑任务时需要获取原先任务的信息,并显示到表单里面
todo=Todo.query.filter_by(id=id).first()
form.content.data=todo.content
form.category.data=todo.category_id
if form.validate_on_submit():
# 更新时获取表单数据一定要使用request.form方法获取,
# 而form.content.data并不能获取用户更新后提交的表单内容;
content=request.form.get('content')
category_id=request.form.get('category')
# 更新到数据库里面
todo.content=content
todo.category_id=category_id
db.session.add(todo)
db.session.commit()
flash('任务已更新',category='success')
return redirect(url_for('todo.list'))
return render_template('todo/edit.html',form=form)
# 删除任务,根据任务id删除
@todo.route('/delete/<int:id>')
@login_required
def delete(id):
todo=Todo.query.filter_by(id=id).first()
db.session.delete(todo)
db.session.commit()
flash('删除任务成功',category='success')
return redirect(url_for('todo.list'))
# 修改任务状态为完成
@todo.route('/done/<int:id>')
@login_required
def done(id):
todo=Todo.query.filter_by(id=id).first()
todo.status=True
db.session.add(todo)
db.session.commit()
flash('修改状态成功',category='success')
return redirect(url_for('todo.list'))
# 修改任务状态为未完成
@todo.route('/undo/<int:id>')
@login_required
def undo(id):
todo=Todo.query.filter_by(id=id).first()
todo.status=False
db.session.add(todo)
db.session.commit()
flash('修改状态成功',category='success')
return redirect(url_for('todo.list'))
@todo.route('/category/add/', methods=['GET', 'POST'])
@login_required
def category_add():
form = AddCategoryForm()
if form.validate_on_submit():
# 获取用户提交的内容
content = form.content.data
# 添加到数据库中
category = Category(name=content,
user_id=current_user.id
)
db.session.add(category)
flash('添加分类成功', category='success')
return redirect(url_for('todo.category_add'))
print(Category.query.all())
return render_template('todo/category_add.html', form=form)
# 查看任务
@todo.route('/category/list/')
@login_required
def category_list(page=1):
print(page)
# 任务显示需要分页,每个用户只能查看自己的任务
categoryPageObj = Category.query.filter_by(
user_id=current_user.id).paginate(
# 在config.py文件中有设置;
page, per_page=current_app.config['PER_PAGE'])
return render_template('todo/category_list.html', categoryPageObj=categoryPageObj)
四、分页展示
- 视图函数
app/todo/views.py中
# 查看任务
@todo.route('/list/')
@login_required
def list():
form = AddTodoForm() # 添加任务之前首先有一个表单,这里实例化了在forms文件中的表单类
# 任务显示需要分页,每个用户只能查看自己的任务
page=int(request.args.get('page',1)) # request获取用户传入的参数,由于页数是整型,所以int()
todoPageobj=Todo.query.filter_by(
user_id=current_user.id).paginate(
# 在config.py文件中设置PER_PAGE=5
# paginate设置分页,page表示显示几页,per_page表示显示多少条数据
page,per_page=current_app.config['PER_PAGE']
)
return render_template('todo/list.html',todoObj=todoPageobj,form=form)
- 前端页面
{% if paginate.has_prev %}
<a href="{{ url_for('user.list') }}?page={{ paginate.prev_num }}">上一页</a>
{% endif %}
{% for i in paginate.iter_pages() %}
<a href="{{ url_for('user.list') }}?page={{ i }}">
{% if not i %}
...
{% else %}
{{ i }}
{% endif %}
</a>
{% endfor %}
{% if paginate.has_next %}
<a href="{{ url_for('user.list') }}?page={{ paginate.next_num }}">下一页</a>
{% endif %}