当前位置:   article > 正文

【python】Flask网页开发——论坛项目实战(完整代码)_flask实战项目

flask实战项目

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

【论坛项目实战】
【python】Flask网页开发——论坛项目实战(完整代码)
【python】Flask网页开发——论坛项目实战(1.导航条实现)
【python】Flask网页开发——论坛项目实战(2.登录与注册)
【python】Flask网页开发——论坛项目实战(3.问答模块)

项目展示

页面展示

首页
在这里插入图片描述
发布问答
在这里插入图片描述
登录
在这里插入图片描述
注册
在这里插入图片描述
问答详情
在这里插入图片描述

具体实现

1.导航条实现

2.登录与注册

3.问答模块

项目结构

1.创建项目

在这里插入图片描述

2.项目需要提前安装的包

  • pymysql:Python操作数据库的驱动程序
  • Flask-SQLAlchemy:在Flask中使用ORM模型操作数据库
  • cryptography:对密码进行加密和解密
  • Flask-Migrate:将ORM模型的变更同步到数据库中
  • WTForms:用于处理表单的Python库
  • Flask-Mail : Flask 框架的一个扩展,用于在 Web 应用程序中发送电子邮件。

3.项目结构

在这里插入图片描述

blueprints

forms.py

import wtforms
from wtforms.validators import length, email, EqualTo
from models.models import EmailCaptchaModel, UserModel


class LoginForm(wtforms.Form):
    email = wtforms.StringField(validators=[email()])
    password = wtforms.StringField(validators=[length(min=6, max=20)])


class RegisterForm(wtforms.Form):
    username = wtforms.StringField(validators=[length(min=3, max=20)])
    email = wtforms.StringField(validators=[email()])
    captcha = wtforms.StringField(validators=[length(min=4, max=4)])
    password = wtforms.StringField(validators=[length(min=6, max=20)])
    confirm_password = wtforms.StringField(validators=[EqualTo("password")])

    def validate_captcha(self, field):
        captcha = field.data
        email = self.email.data
        captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
        if not captcha_model or captcha_model.captcha.lower() != captcha.lower():
            raise wtforms.ValidationError("邮箱验证码错误!")

    def validate_email(self, field):
        email = field.data
        user_model = UserModel.query.filter_by(email=email).first()
        if user_model:
            raise wtforms.ValidationError("邮箱已存在!")


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)])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

user.py

from datetime import datetime
from flask import Blueprint, render_template, request, redirect, url_for, jsonify, session, flash
from exts import mail
from flask_mail import Message
from models.models import EmailCaptchaModel, UserModel
import string
import random
from exts import db
from .forms import RegisterForm, LoginForm
from werkzeug.security import generate_password_hash, check_password_hash

bp = Blueprint("user", __name__, url_prefix="/user")


@bp.route("/login", methods=['GET', 'POST'])
def login():    # 登录
    if request.method == 'GET':
        return render_template("login.html")
    else:
        form = LoginForm(request.form)  # 存储前端表单的内容
        if form.validate():
            email = form.email.data
            password = form.password.data
            user = UserModel.query.filter_by(email=email).first()
            if user and check_password_hash(user.password, password):
                session['user_id'] = user.id
                return redirect("/")
            else:
                flash("邮箱和密码不匹配!")
                return redirect(url_for("user.login"))
        else:
            flash("格式错误!")
            return redirect(url_for("user.login"))


@bp.route("/register", methods=
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/51376
推荐阅读
相关标签
  

闽ICP备14008679号