【python】Flask网页开发——论坛项目实战(3.问答模块)

笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~

【论坛项目实战】
【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

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zz的学习笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值