一、创建问题模型
models.py
class QuestionModel(db.Model): __tablename__ = "question" id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(100), nullable=False) content = db.Column(db.Text, nullable=False) create_time = db.Column(db.DateTime, default=datetime.now) # 外键 author_id = db.Column(db.Integer, db.ForeignKey("user.id")) author = db.relationship(UserModel, backref="questions")
迁移更新数据库
flask db migrate
flask db upgrade
详情见:Flask(Mysql)——ORM模型外键与表的关系及用flask_migrate迁移ORM模型-CSDN博客
二、路由请求
qa.py
from flask import Blueprint, request, render_template, g, redirect, url_for from .forms import QuestionForm from models import QuestionModel from exts import db @bp.route("/qa/public", methods=['GET', 'POST']) @login_required def public_question(): if request.method == 'GET': return render_template("public_question.html") else: form = QuestionForm(request.form) if form.validate(): title = form.title.data content = form.content.data question = QuestionModel(title=title, content=content, author=g.user) db.session.add(question) db.session.commit() # todo: 跳转到这篇问答的详情页 return redirect("/") else: print(form.errors) return redirect(url_for("qa.public_question"))
三、问题表单验证
froms.py
class QuestionForm(wtforms.Form): title = wtforms.StringField(validators=[Length(min=3, max=100, message="标题格式错误!")]) content = wtforms.StringField(validators=[Length(min=3,message="内容格式错误!")])
四、登录装饰器
防止用户没有登录也能发布问答
新建decorators.py文件
from functools import wraps from flask import g, redirect, url_for def login_required(func): # 保留func的信息 @wraps(func) # func(a,b,c) # func(1,2,c=3) def inner(*args, **kwargs): if g.user: return func(*args, **kwargs) else: return redirect(url_for("auth.login")) return inner
检查全局变量g中的user属性是否存在。如果存在,说明用户已经登录,可以访问被修饰的视图函数;如果不存在,说明用户未登录,将被重定向到登录页面。
五、问答列表详情
新建问题详情跳转路由
qa.py
@bp.route("/qa/detail/<qa_id>")
def qa_detail(qa_id):
question = QuestionModel.query.get(qa_id)
return render_template("detail.html", question=question)
index.html
<div class="question-title"><a href="{ { url_for('qa.qa_detail', qa_id=question.id) }}">{ { question.title }}</a></div>
六、创建答案模型
models.py
class AnswerModel(db.Model): __tablename__ = "answer" id = db.Column(db.Integer, primary_key=True, autoincrement=True) content = db.Column(db.Text, nullable=False) create_time = db.Column(db.DateTime, default=datetime.now) # 外键 question_id = db.Column(db.Integer, db.ForeignKey("question.id")) author_id = db.Column(db.Integer, db.ForeignKey("user.id")) # 关系 question = db.relationship(QuestionModel, backref=db.backref("answers", order_by=create_time.desc())) author = db.relationship(UserModel, backref="answers")
迁移更新数据库
flask db migrate
flask db upgrade
七、答案表单验证
forms.py
from wtforms.validators import Email, Length, EqualTo, InputRequired class AnswerForm(wtforms.Form): content = wtforms.StringField(validators=[Length(min=3, message="内容格式错误!")]) question_id = wtforms.IntegerField(validators=[InputRequired(message="必须要传入问题id!")])
qa.py
from .forms import QuestionForm, AnswerForm from models import QuestionModel, AnswerModel # @bp.route("/answer/public", methods=['POST']) @bp.post("/answer/public") @login_required def public_answer(): form = AnswerForm(request.form) if form.validate(): content = form.content.data question_id = form.question_id.data answer = AnswerModel(content=content, question_id=question_id, author_id=g.user.id) db.session.add(answer) db.session.commit() return redirect(url_for("qa.qa_detail", qa_id=question_id)) else: print(form.errors) return redirect(url_for("qa.qa_detail", qa_id=request.form.get("question_id")))
detail.html 前端详情页面表单
<form action="{ { url_for('qa.public_answer') }}" method="post"> <div class="form-group"> <input type="text" placeholder="请填写评论" name="content" class="form-control"> <input type="hidden" name="question_id" value="{ { question.id }}"> </div> <div class="form-group" style="text-align: right;"> <button class="btn btn-primary">评论</button> </div> </form>
八、搜索功能实现
1、qa.py 创建搜索路由
@bp.route("/search") def search(): # /search?q=flask # /search/<q> # post, request.form q = request.args.get("q") questions = QuestionModel.query.filter(QuestionModel.title.contains(q)).all() return render_template("index.html", questions=questions)
2、base.html
<li class="nav-item ml-2"> <form class="form-inline my-2 my-lg-0" method="GET" action="{ { url_for('qa.search') }}"> <input class="form-control mr-sm-2" type="search" placeholder="关键字" aria-label="Search" name="q"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button> </form> </li>
项目完结........