笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~
【论坛项目实战】
【python】Flask网页开发——论坛项目实战(完整代码)
【python】Flask网页开发——论坛项目实战(1.导航条实现)
【python】Flask网页开发——论坛项目实战(2.登录与注册)
【python】Flask网页开发——论坛项目实战(3.问答模块)
问答模块
问答模块
blueprints
qa.py
from flask import Blueprint, render_template, request, g, redirect, url_for, flash
from decorators import login_required
from exts import db
from .forms import QuestionForm,AnswerForm
from models.models import QuestionModel, AnswerModel
from sqlalchemy import or_
bp = Blueprint("qa", __name__, url_prefix="/")
@bp.route("/")
def index():
questions = QuestionModel.query.order_by(db.text("-create_time")).all()
return render_template("index.html", questions=questions)
@bp.route("/question/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()
return redirect("/")
else:
flash("标题或内容格式错误!")
return redirect(url_for("qa.public_question"))
@bp.route("/question/<int:question_id>")
def question_detail(question_id):
question = QuestionModel.query.get(question_id)
return render_template("detail.html", question=question)
@bp.route("/answer/<int:question_id>", methods=['POST'])
@login_required # 装饰器
def answer(question_id): # 注册
form = AnswerForm(request.form) # 存储前端表单的内容
if form.validate():
content = form.content.data
answer_model = AnswerModel(content=content, author=g.user, question_id=question_id)
db.session.add(answer_model)
db.session.commit()
return redirect(url_for("qa.question_detail", question_id=question_id))
else:
flash("请填写评论再提交!")
return redirect(url_for("qa.question_detail", question_id=question_id))
@bp.route("/search")
def search():
kword = request.args.get("kword")
questions = QuestionModel.query.filter(or_(QuestionModel.title.contains(kword),QuestionModel.content.contains(kword))).order_by(db.text("-create_time"))
return render_template("index.html",questions = questions)
forms.py
import wtforms
from wtforms.validators import length, email, EqualTo
from models.models import EmailCaptchaModel, UserModel
class QuestionForm(wtforms.Form):
title = wtforms.StringField(validators=[length(min=3, max=200)])
content = wtforms.StringField(validators=[length(min=5)])
class AnswerForm(wtforms.Form):
content = wtforms.StringField(validators=[length(min=1)])
models
models.py
from exts import db
from datetime import datetime
class QuestionModel(db.Model):
__tablename__ = "question"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text, nullable=False)
create_time = db.Column(db.DateTime(100), default=datetime.now)
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
author = db.relationship("UserModel", backref="questions")
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(100), 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")
templates
index.html
{% extends "base.html" %}
{% block title %}论坛首页{% endblock %}
{% block head %}{% endblock %}
{% block body %}
<div class="row mt-4 justify-content-md-center">
<div class="col"></div>
<div class="col-6">
<div class="card">
{% for question in questions %}
<div class="card-header">
<a href="{{ url_for('qa.question_detail',question_id=question.id) }}">{{ question.title}}</a>
</div>
<div class="card-body">
{{ question.content}}
<div class="blockquote-footer" style="text-align:right">
<span>{{ question.author.username}}</span>
<span style="text-align:right">{{ question.create_time}}</span>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="col"></div>
</div>
{% endblock %}
public_question.html
{% extends "base.html" %}
{% block title %}发布问答{% endblock %}
{% block body %}
<div class="row mt-4">
<div class="col"></div>
<div class="col-8">
<h1 style="text-align:center">发布问答</h1>
<form action="{{ url_for('qa.public_question') }}" method="post">
<div class="form-group">
<input type="text" name="title" class="form-control" placeholder="请输入标题">
</div>
<div class="form-group">
<textarea name="content" class="form-control" id="" cols="30" rows="10"
placeholder="请输入内容"></textarea>
</div>
{% for message in get_flashed_messages() %}
<div class="form-group">
<div class="text-danger">{{ message }}</div>
</div>
{% endfor %}
<div class="form-group" style="text-align:right">
<button class="btn btn-primary">发布</button>
</div>
</form>
</div>
<div class="col"></div>
</div>
{% endblock %}
detail.html
{% extends "base.html" %}
{% block title %}{{ question.title }}{% endblock %}
{% block head %}{% endblock %}
{% block body %}
<div class="row mt-4 justify-content-md-center">
<div class="col"></div>
<div class="col-6">
<div class="card">
<div class="card-header" style="text-align:center">
<h3>{{ question.title}}</h3>
<span>作者:{{ question.author.username}}</span>
<span style="text-align:right">时间:{{ question.create_time}}</span>
</div>
<div class="card-body">
{{ question.content}}
</div>
<div class="card-footer">
<h4>评论({{ question.answers|length }})</h4>
<form action="{{ url_for('qa.answer',question_id=question.id) }}" method="post">
<div class="form-group">
<input type="text" placeholder="请填写评论" name="content" class="form-control">
</div>
{% for message in get_flashed_messages() %}
<div class="form-group">
<div class="text-danger">{{ message }}</div>
</div>
{% endfor %}
<div class="form-group" style="text-align:right;">
<button class="btn btn-primary">评论</button>
</div>
</form>
<div class="list-group ">
<div class="border border-bottom-0" style="padding:10px">
{% for answer in question.answers %}
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{ answer.author.username }}</h5>
<small>{{ answer.create_time }}</small>
</div>
<p class="mb-1">{{ answer.content }}</p>
<hr color="black">
{% endfor %}
</div>
</div>
</div>
</div>
</div>
<div class="col"></div>
</div>
{% endblock %}
decorators.py
from flask import g, redirect, url_for
from functools import wraps
def login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if hasattr(g, "user"):
return func(*args, **kwargs)
else:
return redirect(url_for("user.login"))
return wrapper