发布帖子
@bp.route("/post/public", methods=['GET', 'POST'])
@login_required
def public_post():
if request.method == 'GET':
# 获取所有模板数据
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
return render_template("front/public_post.html", boards=boards)
校验富文本编辑器上传的图片
class UploadImageForm(BaseForm):
image = FileField(validators=[FileAllowed(['jpg', 'jpeg', 'png'], message="图片格式不符合要求!"), FileSize(max_size=1024*1024*5, message="图片最大不能超过5M!")])
新建post目录用来存放帖子图片
在config配置文件中添加帖子图片地址
# 帖子图片存放路径
POST_IMAGE_SAVE_PATH = os.path.join(BASE_DIR, "media", "post")
wangedit返回图片的数据格式
富文本编辑器上传图片
@bp.post("/post/image/upload")
@login_required
def upload_post_image():
form = UploadImageForm(request.files)
if form.validate():
image = form.image.data
# 不要使用用户上传上来的文件名,否则容易被黑客攻击
filename = image.filename
# xxx.png,xx.jpeg
_, ext = os.path.splitext(filename)
filename = md5((g.user.email + str(time.time())).encode("utf-8")).hexdigest() + ext
image_path = os.path.join(current_app.config['POST_IMAGE_SAVE_PATH'], filename)
image.save(image_path)
# {"data","code", "message"}
return jsonify({"errno": 0, "data": [{
"url": url_for("media.get_post_image", filename=filename),
"alt": filename,
"href": ""
}]})
else:
message = form.messages[0]
return restful.params_error(message=message)
为后面nginx映射做准备
@bp.route("/post/<filename>")
def get_post_image(filename):
return send_from_directory(current_app.config['POST_IMAGE_SAVE_PATH'], filename)
发布帖子
@bp.route("/post/public", methods=['GET', 'POST'])
@login_required
def public_post():
if request.method == 'GET':
# 获取所有模板数据
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
return render_template("front/public_post.html", boards=boards)
else:
form = PublicPostForm(request.form)
if form.validate():
title = form.title.data
content = form.content.data
board_id = form.board_id.data
try:
# get方法:接收一个id作为参数,如果找到了,那么会返回这条数据
# 如果没有找到,那么会抛出异常
board = BoardModel.query.get(board_id)
except Exception as e:
return restful.params_error(message="板块不存在!")
post_model = PostModel(title=title, content=content, board=board, author=g.user)
db.session.add(post_model)
db.session.commit()
# 返回帖子的id
return restful.ok(data={"id": post_model.id})
else:
return restful.params_error(message=form.messages[0])
校验发布帖子的参数
class PublicPostForm(BaseForm):
title = StringField(validators=[Length(min=3, max=200, message="帖子标题必须在3-200之间!")])
content = StringField(validators=[InputRequired(message="请传入内容!")])
board_id = IntegerField(validators=[InputRequired(message="请传入板块ID!")])
发布帖子成功后根据后端返回的帖子id 跳转到帖子详情
帖子详情API
@bp.get("/post/detail/<post_id>")
def post_detail(post_id):
post_model = PostModel.query.get(post_id)
comment_count = CommentModel.query.filter_by(post_id=post_id).count()
context = {
"comment_count": comment_count,
"post": post_model
}
return render_template("front/post_detail.html", **context)
获得帖子详情
点击帖子传递帖子id获得详情
@bp.get("/post/detail/<int:post_id>")
def post_detail(post_id):
try:
# 根据帖子的id查询帖子信息
post_model = PostModel.query.get(post_id)
except:
return '404'
comment_count = CommentModel.query.filter_by(post_id=post_id).count()
context = {
"comment_count": comment_count,
"post": post_model
}
return render_template("front/post_detail.html", **context)
帖子详情页代码的高亮
使用第三方库
https://highlightjs.org/
发表评论
参数校验
class PublicCommentForm(BaseForm):
content = StringField(validators=[InputRequired(message="请传入内容!")])
post_id = IntegerField(validators=[InputRequired(message="请传入帖子ID!")])
@bp.post("/comment")
@login_required
def public_comment():
form = PublicCommentForm(request.form)
# 校验表单
if form.validate():
content = form.content.data
post_id = form.post_id.data
try:
post_model = PostModel.query.get(post_id)
except Exception as e:
return restful.params_error(message="帖子不存在!")
comment = CommentModel(content=content, post_id=post_id, author_id=g.user.id)
db.session.add(comment)
db.session.commit()
return restful.ok()
else:
message = form.messages[0]
return restful.params_error(message=message)
首页获取所有帖子
@bp.route('/')
def index():
# 获得板块后根据优先级进行排序从大到小
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
# 获取所有帖子
posts = PostModel.query.order_by(PostModel.create_time.desc())
context = {
"boards": boards,
"posts": posts,
}
return render_template("front/index.html", **context)
帖子分页
首先我们可以批量生成帖子
commands
# 批量生成帖子
def create_test_posts():
boards = list(BoardModel.query.all())
board_count = len(boards)
for x in range(99):
title = "我是标题%d"%x
content = "我是内容%d"%x
author = UserModel.query.first()
index = random.randint(0, board_count-1)
board = boards[index]
post_model = PostModel(title=title, content=content, author=author,board=board)
db.session.add(post_model)
db.session.commit()
print("测试帖子添加成功")
app.py注册
app.cli.command("create_test_posts")(commands.create_test_posts)
pip install flask-paginate
@bp.route('/')
def index():
sort = request.args.get("st", type=int, default=1)
# 获得板块后根据优先级进行排序从大到小
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
post_query = None
if sort == 1:
# 按照最近创建的帖子排序
post_query = PostModel.query.order_by(PostModel.create_time.desc())
else:
# 根据评论数量进行排序 帖子评论外连接 根据帖子id分组 计算评论的数量
post_query = db.session.query(PostModel).outerjoin(CommentModel).group_by(PostModel.id).order_by(func.count(CommentModel.id).desc(), PostModel.create_time.desc())
page = request.args.get(get_page_parameter(), type=int, default=1)
# 1:0-9
# 2:10-19
start = (page - 1) * current_app.config['PER_PAGE_COUNT']
end = start + current_app.config['PER_PAGE_COUNT']
# 帖子总数量
total = post_query.count()
posts = post_query.slice(start, end)
pagination = Pagination(bs_version=3, page=page, total=total, prev_label="上一页")
banners = BannerModel.query.order_by(BannerModel.priority.desc()).all()
context = {
"boards": boards,
"posts": posts,
"pagination": pagination,
"st": sort,
"bd": board_id,
"banners": banners
}
return render_template("front/index.html", **context)
根据板块分页
@bp.route('/')
def index():
sort = request.args.get("st", type=int, default=1)
# 板块id
board_id = request.args.get("bd", type=int, default=None)
# 获得板块后根据优先级进行排序从大到小
boards = BoardModel.query.order_by(BoardModel.priority.desc()).all()
post_query = None
if sort == 1:
# 按照最近创建的帖子排序
post_query = PostModel.query.order_by(PostModel.create_time.desc())
else:
# 根据评论数量进行排序 帖子评论外连接 根据帖子id分组 计算评论的数量
post_query = db.session.query(PostModel).outerjoin(CommentModel).group_by(PostModel.id).order_by(func.count(CommentModel.id).desc(), PostModel.create_time.desc())
page = request.args.get(get_page_parameter(), type=int, default=1)
# 1:0-9
# 2:10-19
start = (page - 1) * current_app.config['PER_PAGE_COUNT']
end = start + current_app.config['PER_PAGE_COUNT']
# 如果有板块id 就在之前的基础上再进行过滤
if board_id:
# "mapped class CommentModel->comment" has no property "board_id"
# CommentModel中寻找board_id,然后进行过滤
# post_query = post_query.filter_by(board_id=board_id)
post_query = post_query.filter(PostModel.board_id==board_id)
# 帖子总数量
total = post_query.count()
posts = post_query.slice(start, end)
pagination = Pagination(bs_version=3, page=page, total=total, prev_label="上一页")
banners = BannerModel.query.order_by(BannerModel.priority.desc()).all()
context = {
"boards": boards,
"posts": posts,
"pagination": pagination,
"st": sort,
"bd": board_id,
"banners": banners
}
return render_template("front/index.html", **context)