IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Flask-07(钩子函数和上下文处理器和退出登录 访问限制 发布 进入发布内容详情和评论) -> 正文阅读

[Python知识库]Flask-07(钩子函数和上下文处理器和退出登录 访问限制 发布 进入发布内容详情和评论)

钩子函数和上下文处理器和退出登录

from flask import Flask, Response, request, session, render_template,g
import config
from exts import db,mail
from blueprints import qa_bp
from blueprints import user_bp
from flask_migrate import Migrate

from models import UserModel

app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)
mail.init_app(app)
migrate=Migrate(app,db)

app.register_blueprint(qa_bp)
app.register_blueprint(user_bp)

@app.before_request
def before_request():
    user_id = session.get("user_id")
    if user_id:
        try:
            user = UserModel.query.get(user_id)
            # 给g绑定一个叫做user的变量,他的值是user这个变量
            #setattr(g,"user",user)
            g.user = user
        except:
            g.user = None

# 请求来了 -> before_request -> 视图函数 -> 视图函数中返回模板 -> context_processor
@app.context_processor
def context_processor():
    if hasattr(g,"user"):
        return {"user": g.user}
    else:
        return {}

if __name__ == '__main__':
    app.run()

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static',filename='bootstrap/bootstrap.4.6.css') }}">
</head>
<link rel="stylesheet" href="{{ url_for('static',filename='css/init.css') }}">
{% block head %}{% endblock %}
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container">
    <a class="navbar-brand" href="#">?表白墙</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" href="#">首页 <span class="sr-only">(current)</span></a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">树洞</a>
        </li>
        <li class="nav-item ml-3">
          <form class="form-inline my-2 my-lg-0">
            <input class="form-control mr-sm-2" type="search" placeholder="关键字" aria-label="Search">
            <button class="btn btn-outline-success my-2 my-sm-0" type="submit">搜索</button>
          </form>
        </li>
      </ul>
      <ul class="navbar-nav ">
        {% if user %}
          <li class="nav-item">
            <span class="nav-link">{{ user.username }}</span>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('user.logout') }}">退出登录</a>
          </li>
        {% else %}
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('user.login') }}">登录</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="{{ url_for('user.register') }}">注册</a>
          </li>
        {% endif %}

      </ul>
    </div>
  </div>
</nav>
<div class="container">
  {% block body %}
  {% endblock %}
</div>
</body>
</html>
import random
import string

from flask import (Blueprint,
                   render_template,
                   request, redirect,
                   url_for,
                   jsonify,
                   session,
                   flash)

from blueprints.forms import RegisterForm,LoginForm
from exts import mail, db
from flask_mail import Message
from models import EmailCaptchaModel, UserModel
from datetime import datetime
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=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template("register.html")
    else:
        form = RegisterForm(request.form)
        if form.validate():
            email = form.email.data
            username = form.username.data
            password = form.password.data
            # md5利用hash加密
            hash_password = generate_password_hash(password)
            user = UserModel(email=email, username=username, password=hash_password)
            db.session.add(user)
            db.session.commit()
            return redirect(url_for("user.login"))
        else:
            return redirect(url_for("user.register"))

@bp.route("/logout")
def logout():
    # 清除session中所有的数据
    session.clear()
    return redirect(url_for('user.login'))

@bp.route("/captcha", methods=['POST'])
def get_captcha():
    # GET,POST
    email = request.form.get("email")
    letters = string.ascii_letters + string.digits
    captcha = "".join(random.sample(letters, 4))
    if email:
        message = Message(
            subject="这是一封很有味道的邮件",
            recipients=[email],
            body=f"哈咯哈咯,您宝贵的码是:{captcha},请不要告诉任何人哦!"
        )
        mail.send(message)
        captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
        if captcha_model:
            captcha_model.captcha = captcha
            captcha_model.create_time = datetime.now()
            db.session.commit()
        else:
            captcha_model = EmailCaptchaModel(email=email, captcha=captcha)
            db.session.add(captcha_model)
            db.session.commit()
        print("captcha:", captcha)
        # code: 200,成功的、正常的请求
        return jsonify({"code": 200})
    else:
        # code:400,客户端错误
        return jsonify({"code": 400, "message": "请先传递邮箱!"})

在这里插入图片描述

访问限制

功能:完善用户未登录即可发布评论的功能。
用一个decorators.py装饰器,再在qa.py中导入该功能即可。
decorators.py:

from flask import g,redirect,url_for
from functools import wraps


# 装饰器用于判断是否登录,如果没有登录,跳转到登录页面


def login_required(func):
    # @wraps这个装饰器一定不要忘记写了
    @wraps(func)
    def wrapper(*args,**kwargs):
        if hasattr(g,'user'):
            return func(*args,**kwargs)
        else:
            return redirect(url_for("user.login"))

    return wrapper

user.py

import random
import string

from flask import (Blueprint,
                   render_template,
                   request, redirect,
                   url_for,
                   jsonify,
                   session,
                   flash)

from blueprints.forms import RegisterForm,LoginForm
from exts import mail, db
from flask_mail import Message
from models import EmailCaptchaModel, UserModel
from datetime import datetime
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=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template("register.html")
    else:
        form = RegisterForm(request.form)
        if form.validate():
            email = form.email.data
            username = form.username.data
            password = form.password.data
            # md5利用hash加密
            hash_password = generate_password_hash(password)
            user = UserModel(email=email, username=username, password=hash_password)
            db.session.add(user)
            db.session.commit()
            return redirect(url_for("user.login"))
        else:
            return redirect(url_for("user.register"))

@bp.route("/logout")
def logout():
    # 清除session中所有的数据
    session.clear()
    return redirect(url_for('user.login'))

@bp.route("/captcha", methods=['POST'])
def get_captcha():
    # GET,POST
    email = request.form.get("email")
    letters = string.ascii_letters + string.digits
    captcha = "".join(random.sample(letters, 4))
    if email:
        message = Message(
            subject="这是一封很有味道的邮件",
            recipients=[email],
            body=f"哈咯哈咯,您宝贵的码是:{captcha},请不要告诉任何人哦!"
        )
        mail.send(message)
        captcha_model = EmailCaptchaModel.query.filter_by(email=email).first()
        if captcha_model:
            captcha_model.captcha = captcha
            captcha_model.create_time = datetime.now()
            db.session.commit()
        else:
            captcha_model = EmailCaptchaModel(email=email, captcha=captcha)
            db.session.add(captcha_model)
            db.session.commit()
        print("captcha:", captcha)
        # code: 200,成功的、正常的请求
        return jsonify({"code": 200})
    else:
        # code:400,客户端错误
        return jsonify({"code": 400, "message": "请先传递邮箱!"})

在这里插入图片描述
退出登录之后无法访问。
在这里插入图片描述

发布

1.在树洞创建一个前端界面public_question.html:

<!DOCTYPE html>
{% extends "base.html" %}

{% block title %}?表白墙-首页{% endblock %}
{% block body %}
  <div class="row" style="margin-top: 20px;">
    <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" rows="10" placeholder="请输入内容,至少5个字哦"></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 %}

在这里插入图片描述

2.需要在数据库中创建一个表储存用户发的树洞。
利用model.py创建表的模板

from exts import db
from datetime import datetime


class EmailCaptchaModel(db.Model):
    __tablename__ = "email_captcha"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    email = db.Column(db.String(100), nullable=False, unique=True)
    captcha = db.Column(db.String(10), nullable=False)
    create_time = db.Column(db.DateTime, default=datetime.now)


class UserModel(db.Model):
    __tablename__ = "user"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(200), nullable=False, unique=True)
    email = db.Column(db.String(100), nullable=False, unique=True)
    password = db.Column(db.String(200), nullable=False)
    join_time = db.Column(db.DateTime, default=datetime.now)

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,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在数据库中创建该表
在这里插入图片描述

3.因为用户发表的树洞需要显示在主页上,所以修改一下主页的前端界面。
index.css

.question-ul li{
    padding: 10px;
    overflow: hidden;
    display: flex;
    background-color: #fff;
    border-bottom:1px solid #eee;
}
.side-question{
    flex-basis: 38px;
    height:100%;
}
.side-question-avatar{
    width: 38px;
    height:38px;
    border-radius: 3px;
}

.question-main{
    flex: 1;
    width: 660px;
    margin-left:10px;
    overflow: hidden;
}

.question-title a{
    color: #259;
    font-size:14px;
    font-weight: 900;
}
.question-author{
    font-size: 12px;
    margin-top: 5px;
}
.question-content{
    margin-top: 5px;
    font-size:12px;
}
.question-detail{
    text-align: right;
    margin-top: 10px;
}
.question-detail .question-author{
    margin-right:10px;
}

index.html

{% extends "base.html" %}

{% block title %}知了问答-首页{% endblock %}

{% block head %}
  <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}">
{% endblock %}

{% block body %}
  <div class="row" style="margin-top: 20px;">
    <div class="col"></div>
    <div class="col-8">
      <ul class="question-ul">
        {% for question in questions %}
          <li>
            <div class="side-question">
              <img class="side-question-avatar" src="{{ url_for('static',filename='images/img.png') }}" alt="">
            </div>
            <div class="question-main">
              <div class="question-title"><a
                      href="#">{{ question.title }}</a></div>
              <div class="question-content">{{ question.content }}</div>
              <div class="question-detail">
                <span class="question-author">{{ question.author.username }}</span>
                <span class="question-time">{{ question.create_time }}</span>
              </div>
            </div>
          </li>
        {% endfor %}
      </ul>
    </div>
    <div class="col"></div>
  </div>
{% endblock %}

4.在forms.py中设QuestionModels的类,查询用户输入的话是否符合格式:

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

class QuestionForm(wtforms.Form):
    title = wtforms.StringField(validators=[length(min=3, max=200)])
    content = wtforms.StringField(validators=[length(min=5)])

进入发布内容详情和评论

1.在model.py创建一个AnswerModel的模型,映射到数据库中

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

在这里插入图片描述
在这里插入图片描述
2.在qa.py中添加可视化

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

3.新建detail.html显示详情界面

{% extends "base.html" %}

{% block title %}{{ question.title }}{% endblock %}


{% block head %}
  <link rel="stylesheet" href="{{ url_for('static',filename='css/detail.css') }}">
{% endblock %}


{% block body %}
  <div class="row" style="margin-top: 20px;">
    <div class="col"></div>
    <div class="col-8" style="background-color: #fff;padding: 20px;">
      <h3 class="page-title">{{ question.title }}</h3>
      <p class="question-info">
        <span>发布人:{{ question.author.username }}</span>
        <span>时间:{{ question.create_time }}</span>
      </p>
      <hr>
      <p class="question-content">{{ question.content }}</p>
      <hr>

      <h4 class="comment-group-title">评论({{ 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>
      <ul class="comment-group">
        {% for answer in question.answers %}
          <li>
            <div class="user-info">
              <img class="avatar" src="{{ url_for('static',filename='images/img.png') }}" alt="">
              <span class="username">{{ answer.author.username }}</span>
              <span class="create-time">{{ answer.create_time }}</span>
            </div>
            <p class="comment-content">{{ answer.content }}</p>
          </li>
        {% endfor %}
      </ul>
    </div>
    <div class="col"></div>
  </div>
{% endblock %}

4.在index.html主页中添加进入详情页的连接

{% extends "base.html" %}

{% block title %}?表白墙-首页{% endblock %}

{% block head %}
  <link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}">
{% endblock %}

{% block body %}
  <div class="row" style="margin-top: 20px;">
    <div class="col"></div>
    <div class="col-8">
      <ul class="question-ul">
        {% for question in questions %}
          <li>
            <div class="side-question">
              <img class="side-question-avatar" src="{{ url_for('static',filename='images/img.png') }}" alt="">
            </div>
            <div class="question-main">
              <div class="question-title"><a
                      href="{{ url_for('qa.question_detail',question_id=question.id) }}">{{ question.title }}</a></div>
              <div class="question-content">{{ question.content }}</div>
              <div class="question-detail">
                <span class="question-author">{{ question.author.username }}</span>
                <span class="question-time">{{ question.create_time }}</span>
              </div>
            </div>
          </li>
        {% endfor %}
      </ul>
    </div>
    <div class="col"></div>
  </div>
{% endblock %}

在这里插入图片描述
在这里插入图片描述

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:11:19  更:2022-10-22 21:11:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 6:46:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码