赞
踩
先创建一个配置文件config.py,后面有些配置写在这里
#app.py
from flask import Flask
import config
app = Flask(__name__)
#绑定配置文件
app.config.from_object(config)
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
if __name__ == '__main__':
app.run()
再新建一个exts.py和models.py
#exts.py #flask-sqlalchemy from flask_sqlalchemy import SQLAlchemy db=SQLAlchemy() #models.py from exts import db class UserModel(db.Model): pass #app.py from flask import Flask import config from exts import db from models import UserModel app = Flask(__name__) #绑定配置文件 app.config.from_object(config) #可以让你先创建,再绑定 db.init_app(app) @app.route('/') def hello_world(): # put application's code here return 'Hello World!' if __name__ == '__main__': app.run()
防止循环引用,如果不加exts.py会导致下面这种情况
加了就可以变成这样子
下面设置蓝图,用来做模块化的
再在这里新建两个py文件,一个是auth.py和授权相关的,一个是qa.py和问答相关的
#auth.py from flask import Blueprint # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @bp.route("/login") def login(): pass #qa.py from flask import Blueprint bp=Blueprint("qa",__name__,url_prefix="/") @bp.route("/") def index(): pass
再在app.py中导入和绑定
#app.py from flask import Flask import config from exts import db from models import UserModel from blueprints.qa import bp as qa_bp from blueprints.auth import bp as auth_bp app = Flask(__name__) #绑定配置文件 app.config.from_object(config) #可以让你先创建,再绑定 db.init_app(app) app.register_blueprint(qa_bp) app.register_blueprint(auth_bp) if __name__ == '__main__': app.run()
先在navicat里新建数据库
#config.py # 数据库的配置信息 HOSTNAME = '127.0.0.1' PORT = '3306' USERNAME = 'root' PASSWORD = '123456' DATABASE = 'zhiliaooa_course' DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE) SQLALCHEMY_DATABASE_URI = DB_URI #model.py from exts import db from datetime import datetime class UserModel(db.Model): __tablename__ = "user" id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(100), nullable=False) password = db.Column(db.String(100), nullable=False) email = db.Column(db.String(100), nullable=False) join_time = db.Column(db.DateTime, default=datetime.now) #app.py from flask import Flask import config from exts import db from models import UserModel from blueprints.qa import bp as qa_bp from blueprints.auth import bp as auth_bp from flask_migrate import Migrate app = Flask(__name__) # 绑定配置文件 app.config.from_object(config) # 可以让你先创建,再绑定 db.init_app(app) migrate = Migrate(app, db) app.register_blueprint(qa_bp) app.register_blueprint(auth_bp) if __name__ == '__main__': app.run()
然后运行三步
flask db init(只需第一次操作一下)
flask db migrate
flask db upgrade
然后数据库刷新下就可以看到
我们已经准备好了html文件和其静态样式,将其放入自己的文件内
其中本来只有红框标记的这几个
register.js是为了登录自己写的
base.html是为了减少代码量,能复用父组件base.html写的
(这部分可先跳过,后面会说)
#register.js function bindEmailCaptchaClick(){ $("#captcha-btn").click(function (event){ // $this:代表的是当前按钮的jquery对象 var $this = $(this); // 阻止默认的事件 event.preventDefault(); var email = $("input[name='email']").val(); $.ajax({ // http://127.0.0.1:500 // /auth/captcha/email?email=xx@qq.com url: "/auth/captcha/email?email="+email, method: "GET", success: function (result){ var code = result['code']; if(code == 200){ var countdown = 5; // 开始倒计时之前,就取消按钮的点击事件 $this.off("click"); var timer = setInterval(function (){ $this.text(countdown); countdown -= 1; // 倒计时结束的时候执行 if(countdown <= 0){ // 清掉定时器 clearInterval(timer); // 将按钮的文字重新修改回来 $this.text("获取验证码"); // 重新绑定点击事件 bindEmailCaptchaClick(); } }, 1000); // alert("邮箱验证码发送成功!"); }else{ alert(result['message']); } }, fail: function (error){ console.log(error); } }) }); } // 整个网页都加载完毕后再执行的 $(function (){ bindEmailCaptchaClick(); });
#base.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/bootstrap.4.6.min.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='css/init.css') }}"> {% block head %}{% endblock %} <title>{% block title %}{% endblock %}</title> </head> <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="{{ url_for('qa.index') }}">发布问答</a> </li> <li class="nav-item ml-2"> <form class="form-inline my-2 my-lg-0" method="GET" action="{{ url_for('qa.index') }}"> <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> </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('auth.logout') }}">退出登录</a> </li> {% else %} <li class="nav-item"> <a class="nav-link" href="{{ url_for('auth.login') }}">登录</a> </li> <li class="nav-item"> <a class="nav-link" href="{{ url_for('auth.register') }}">注册</a> </li> {% endif %} </ul> </div> </div> </nav> <div class="container"> {% block body %}{% endblock %} </div> </body> </html>
然后再auth.py里渲染前端页面
from flask import Blueprint,render_template
# /auth,后面所有的路由都是以这个开头,比如/auth/login
bp=Blueprint("auth",__name__,url_prefix="/auth")
@bp.route("/login")
def login():
return "11"
@bp.route("/register")
def register():
return render_template("register.html")
pip install flask_mail
然后准备好qq邮箱,其中一个这样子设置,是邮件的发送方
开启这个服务,我这里是之前已经开启过,如果没有开启的话开启
记住你的授权码
然后再config.py里进行邮箱配置
#邮箱配置
MAIL_SERVER = 'smtp.qq.com'
MAIL_PORT = 465
MAIL_USE_SSL = True
MAIL_USERNAME = '填入你刚刚操作的邮箱'
MAIL_PASSWORD = '填入你刚刚的授权码'
MAIL_DEFAULT_SENDER = '填入你刚刚操作的邮箱,和上面一致'
接下去进行如下操作
#exts.py # flask-sqlalchemy from flask_sqlalchemy import SQLAlchemy from flask_mail import Mail db = SQLAlchemy() mail = Mail() #app.py from flask import Flask import config from exts import db,mail from models import UserModel from blueprints.qa import bp as qa_bp from blueprints.auth import bp as auth_bp from flask_migrate import Migrate 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(auth_bp) if __name__ == '__main__': app.run()
去auth.py测试一下
from flask import Blueprint,render_template from exts import mail from flask_mail import Message # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @bp.route("/login") def login(): return "11" @bp.route("/register") def register(): return render_template("register.html") @bp.route("mail/test") def mail_test(): message=Message(subject="邮箱测试",recipients=["填入你想发送人的邮箱,自己的也行"],body="这是一条测试邮件") mail.send(message) return "邮件发送成功"
#auth.py import random import string from flask import Blueprint,render_template from exts import mail from flask_mail import Message from flask import request # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @bp.route("/login") def login(): return "11" @bp.route("/register") def register(): return render_template("register.html") @bp.route("/captcha/email") def get_email_captcha(): #/captcha/email/<email> #/captcha/email?email=123@qq.com email=request.args.get("email") #4/6:随机数组、字母、数组和字母的组合 source=string.digits*4 captcha=random.sample(source,4) captcha="".join(captcha) print(captcha) return "success" @bp.route("mail/test") def mail_test(): message=Message(subject="邮箱测试",recipients=["123……@qq.com"],body="这是一条测试邮件") mail.send(message) return "邮件发送成功"
测试了一下验证码获取正常,继续完善
@bp.route("/captcha/email")
def get_email_captcha():
#/captcha/email/<email>
#/captcha/email?email=123@qq.com
email=request.args.get("email")
#4/6:随机数组、字母、数组和字母的组合
source=string.digits*4
captcha=random.sample(source,4)
captcha="".join(captcha)
message = Message(subject="知了传课注册验证码", recipients=[email], body=f"您的验证码是:{captcha}")
mail.send(message)
return "success"
http://127.0.0.1:5000/auth/captcha/email?email=123……@qq.com
网页中输入这段代码
现在有一个问题,如何验证用户提交的邮箱和验证码是否对应且正确
答:memcached/redis用数据库表的方式存储
去model.py新建一个类
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)
captcha = db.Column(db.String(100), nullable=False)
然后终端执行如下代码
数据库里可以看到新建了一个
#auth.py import random import string from flask import Blueprint,render_template,jsonify from exts import mail,db from flask_mail import Message from flask import request from models import EmailCaptchaModel # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @bp.route("/login") def login(): return "11" @bp.route("/register") def register(): return render_template("register.html") @bp.route("/captcha/email") def get_email_captcha(): #/captcha/email/<email> #/captcha/email?email=123@qq.com email=request.args.get("email") #4/6:随机数组、字母、数组和字母的组合 source=string.digits*4 captcha=random.sample(source,4) captcha="".join(captcha) message = Message(subject="知了传课注册验证码", recipients=[email], body=f"您的验证码是:{captcha}") mail.send(message) # 用数据库表的方式存储 email_captcha=EmailCaptchaModel(email=email,captcha=captcha) db.session.add(email_captcha) db.session.commit() #RESTful API #{code:200/400/500,message:"",data:{}} return jsonify({"code":200,"message":"","data":None}) @bp.route("mail/test") def mail_test(): message=Message(subject="邮箱测试",recipients=["1065088270@qq.com"],body="这是一条测试邮件") mail.send(message) return "邮件发送成功"
#register.js function bindEmailCaptchaClick(){ $("#captcha-btn").click(function (event){ // $this:代表的是当前按钮的jquery对象 var $this = $(this); // 阻止默认的事件 event.preventDefault(); var email = $("input[name='email']").val(); $.ajax({ // http://127.0.0.1:500 // /auth/captcha/email?email=xx@qq.com url: "/auth/captcha/email?email="+email, method: "GET", success: function (result){ var code = result['code']; if(code == 200){ var countdown = 5; // 开始倒计时之前,就取消按钮的点击事件 $this.off("click"); var timer = setInterval(function (){ $this.text(countdown); countdown -= 1; // 倒计时结束的时候执行 if(countdown <= 0){ // 清掉定时器 clearInterval(timer); // 将按钮的文字重新修改回来 $this.text("获取验证码"); // 重新绑定点击事件 bindEmailCaptchaClick(); } }, 1000); // alert("邮箱验证码发送成功!"); }else{ alert(result['message']); } }, fail: function (error){ console.log(error); } }) }); } // 整个网页都加载完毕后再执行的 $(function (){ bindEmailCaptchaClick(); });
实现功能如下
这部分是加入倒计时,也就是上面的内容,代码合在一块了
验证用户提交的邮箱和验证码是否对应且正确
pip install flask-wtf
在blueprints文件夹里新建forms.py
#forms.py import wtforms from wtforms.validators import Email,Length,EqualTo from models import UserModel,EmailCaptchaModel from exts import db # Form:主要就是用来验证前端提交的数据是否符合要求 class RegisterForm(wtforms.Form): email=wtforms.StringField(validators=[Email(message="邮箱格式不正确")]) captcha=wtforms.StringField(validators=[Length(min=4,max=4,message="验证码长度必须为4位")]) username=wtforms.StringField(validators=[Length(min=3,max=30,message="用户名长度必须在3-30之间")]) password=wtforms.StringField(validators=[Length(min=6,max=30,message="密码长度必须在6-30之间")]) password_confirm=wtforms.StringField(validators=[EqualTo("password",message="两次密码不一致")]) # 自定义验证: #1、邮箱是否已经被注册 def validate_email(self,field): email=field.data user=UserModel.query.filter_by(email=email).first() if user: raise wtforms.ValidationError(message="邮箱已经被注册") # 2、验证码是否正确 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: raise wtforms.ValidationError(message="邮箱或验证码错误!") # 最好是写一个脚本,自动多长时间清除 # else: # db.session.delete(captcha_model) # db.session.commit()
pip install email_validator
然后记得model.py里的password长度设置成200,因为用哈希加密后会超过原来设置的100,会报错(然后记得重新提交更新下数据库)
#auth.py import random import string from flask import Blueprint,render_template,jsonify,redirect,url_for from exts import mail,db from flask_mail import Message from flask import request from models import EmailCaptchaModel from werkzeug.security import generate_password_hash from .forms import RegisterForm from models import UserModel # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @bp.route("/login") def login(): return "11" # GET:从服务器上获取数据 # POST:将客户端的数据向服务器提交 @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 user=UserModel(email=email,username=username,password=generate_password_hash(password)) db.session.add(user) db.session.commit() return redirect(url_for("auth.login")) else: print(form.errors) return redirect(url_for("auth.register")) @bp.route("/captcha/email") def get_email_captcha(): #/captcha/email/<email> #/captcha/email?email=123@qq.com email=request.args.get("email") #4/6:随机数组、字母、数组和字母的组合 source=string.digits*4 captcha=random.sample(source,4) captcha="".join(captcha) message = Message(subject="知了传课注册验证码", recipients=[email], body=f"您的验证码是:{captcha}") mail.send(message) # 用数据库表的方式存储 email_captcha=EmailCaptchaModel(email=email,captcha=captcha) db.session.add(email_captcha) db.session.commit() #RESTful API #{code:200/400/500,message:"",data:{}} return jsonify({"code":200,"message":"","data":None}) @bp.route("mail/test") def mail_test(): message=Message(subject="邮箱测试",recipients=["1065088270@qq.com"],body="这是一条测试邮件") mail.send(message) return "邮件发送成功"
就是把login.html用base.html复用,然后渲染出来,给的资料里已经操作好了
#app.py
@bp.route("/login")
def login():
return render_template("login.html")
#forms.py新增一个类 class LoginForm(wtforms.Form): email=wtforms.StringField(validators=[Email(message="邮箱格式不正确")]) password=wtforms.StringField(validators=[Length(min=6,max=30,message="密码长度必须在6-30之间")]) #auth.py import random import string from flask import Blueprint,render_template,jsonify,redirect,url_for,session from exts import mail,db from flask_mail import Message from flask import request from models import EmailCaptchaModel from werkzeug.security import generate_password_hash,check_password_hash from .forms import RegisterForm,LoginForm from models import UserModel # /auth,后面所有的路由都是以这个开头,比如/auth/login bp=Blueprint("auth",__name__,url_prefix="/auth") @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 not user: print("邮箱在数据库中不存在") return redirect(url_for("auth.login")) if check_password_hash(user.password,password): #cookie: #cookie中不适合存储太多的数据,只适合存储少量的数据 #cookie一般用来存放登录授权的东西 #flask中的session,是经过加密后存储在cookie中的 session["user_id"]=user.id return redirect("/") else: print("密码错误") return redirect(url_for("auth.login")) else: print(form.errors) return redirect(url_for("auth.login")) # GET:从服务器上获取数据 # POST:将客户端的数据向服务器提交 @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 user=UserModel(email=email,username=username,password=generate_password_hash(password)) db.session.add(user) db.session.commit() return redirect(url_for("auth.login")) else: print(form.errors) return redirect(url_for("auth.register")) @bp.route("/captcha/email") def get_email_captcha(): #/captcha/email/<email> #/captcha/email?email=123@qq.com email=request.args.get("email") #4/6:随机数组、字母、数组和字母的组合 source=string.digits*4 captcha=random.sample(source,4) captcha="".join(captcha) message = Message(subject="知了传课注册验证码", recipients=[email], body=f"您的验证码是:{captcha}") mail.send(message) # 用数据库表的方式存储 email_captcha=EmailCaptchaModel(email=email,captcha=captcha) db.session.add(email_captcha) db.session.commit() #RESTful API #{code:200/400/500,message:"",data:{}} return jsonify({"code":200,"message":"","data":None}) @bp.route("mail/test") def mail_test(): message=Message(subject="邮箱测试",recipients=["1065088270@qq.com"],body="这是一条测试邮件") mail.send(message) return "邮件发送成功" #config.py新增一个 SECRET_KEY="adaasdwedda::@" #输入什么都行
你可以通过f12进去,查看cookie存储情况
#app.py from flask import Flask,session,g import config from exts import db,mail from models import UserModel from blueprints.qa import bp as qa_bp from blueprints.auth import bp as auth_bp from flask_migrate import Migrate 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(auth_bp) # before_request/before_first_request/after_request # hook @app.before_request def my_before_request(): user_id=session.get("user_id") if user_id: user=UserModel.query.get(user_id) setattr(g,"user",user) else: setattr(g,"user",None) @app.context_processor def my_context_processor(): return {"user":g.user} if __name__ == '__main__': app.run()
这两段代码是使用 Python 的 Flask 框架编写的,用于处理Web应用程序的请求和上下文管理。让我分别解释它们的作用:
@app.before_request
装饰器函数:
这是一个 Flask 路由装饰器,用于注册一个在每个请求处理之前执行的函数。具体来说,这段代码定义了一个名为my_before_request
的函数,该函数会在每个请求处理之前执行。在函数内部,它首先尝试从会话(session
)中获取用户ID(user_id),这通常是通过用户登录认证过程中设置的。然后,它检查是否成功获取了用户ID。
- 如果成功获取了用户ID,它使用这个用户ID查询数据库中的用户数据(通过
UserModel.query.get(user_id)
)。然后,使用setattr(g, "user", user)
将用户对象存储在 Flask 的上下文变量g
中,以便在请求处理过程中的其他部分可以轻松地访问用户对象。- 如果未成功获取用户ID(即用户未登录或未认证),它将在上下文变量
g
中设置一个空值用户对象。这个函数的主要目的是在每个请求之前检查用户的登录状态,如果用户已登录,将用户对象存储在
g
上下文变量中,以便后续请求处理可以使用该用户对象。
2.@app.context_processor
装饰器函数:
这是另一个 Flask 装饰器,用于注册一个上下文处理器函数,该函数可以将一些数据添加到模板上下文中,以便在渲染模板时访问这些数据。上下文处理器通常用于在所有模板中共享一些通用数据,以简化模板的代码。
- 这段代码定义了一个名为
my_context_processor
的函数,该函数不接受任何参数。在函数内部,它返回一个字典,其中包含了一个键为 “user” 的项,其值为g.user
,即在前面的my_before_request
函数中设置的用户对象。- 这意味着在渲染模板时,您可以在模板中访问
user
变量,以获取当前登录用户的相关信息。例如,您可以在模板中使用{{ user.username }}
来显示当前登录用户的用户名。总的来说,这两段代码结合使用,用于在每个请求处理之前检查用户的登录状态,并将用户对象存储在上下文变量
g
中,然后在模板中使用上下文处理器函数将用户对象添加到模板上下文中,以便在模板中方便地访问用户信息。这对于构建需要用户认证的 Web 应用程序非常有用。
前端修改部分已改好
#auth.py新增一个
@bp.route("/logout")
def logout():
session.clear()
return redirect("/")
#和base.html的 这部分呼应
<li class="nav-item">
<a class="nav-link" href="{{ url_for('auth.logout') }}">退出登录</a>
</li>
#qa.py
from flask import Blueprint,request,render_template
bp=Blueprint("qa",__name__,url_prefix="/")
@bp.route("/")
def index():
return "00"
@bp.route("/qa/public",methods=['GET','POST'])
def public_qa():
if request.method=='GET':
return render_template("public_question.html")
#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
然后我们就可以写发布问答的逻辑了
先设置表单验证
#forms.py
class QuestionForm(wtforms.Form):
title=wtforms.StringField(validators=[Length(min=3,max=100,message="标题格式错误")])
content=wtforms.StringField(validators=[Length(min=3,message="内容格式错误!")])
然后写问答逻辑
#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=Blueprint("qa",__name__,url_prefix="/") @bp.route("/") def index(): return "00" @bp.route("/qa/public",methods=['GET','POST']) 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: print(form.errors) return redirect(url_for("qa.public_question"))
和config.py同级的地方新建一个decorators.py文件
#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
#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 from decorators import login_required bp=Blueprint("qa",__name__,url_prefix="/") @bp.route("/") def index(): return "00" @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() return redirect("/") else: print(form.errors) return redirect(url_for("qa.public_question"))
#qa.py修改下这里
@bp.route("/")
def index():
questions=QuestionModel.query.order_by(QuestionModel.create_time.desc()).all()
return render_template("index.html",questions=questions)
前端部分修改直接修改好了放在文件夹里的
#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)
#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")
#forms.py import wtforms from wtforms.validators import Email,Length,EqualTo,InputRequired from models import UserModel,EmailCaptchaModel from exts import db # Form:主要就是用来验证前端提交的数据是否符合要求 class RegisterForm(wtforms.Form): email=wtforms.StringField(validators=[Email(message="邮箱格式不正确")]) captcha=wtforms.StringField(validators=[Length(min=4,max=4,message="验证码长度必须为4位")]) username=wtforms.StringField(validators=[Length(min=3,max=30,message="用户名长度必须在3-30之间")]) password=wtforms.StringField(validators=[Length(min=6,max=30,message="密码长度必须在6-30之间")]) password_confirm=wtforms.StringField(validators=[EqualTo("password",message="两次密码不一致")]) # 自定义验证: #1、邮箱是否已经被注册 def validate_email(self,field): email=field.data user=UserModel.query.filter_by(email=email).first() if user: raise wtforms.ValidationError(message="邮箱已经被注册") # 2、验证码是否正确 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: raise wtforms.ValidationError(message="邮箱或验证码错误!") # 最好是写一个脚本,自动多长时间清除 # else: # db.session.delete(captcha_model) # db.session.commit() class LoginForm(wtforms.Form): email=wtforms.StringField(validators=[Email(message="邮箱格式不正确")]) password=wtforms.StringField(validators=[Length(min=6,max=30,message="密码长度必须在6-30之间")]) class QuestionForm(wtforms.Form): title=wtforms.StringField(validators=[Length(min=3,max=100,message="标题格式错误")]) content=wtforms.StringField(validators=[Length(min=3,message="内容格式错误!")]) class AnswerForm(wtforms.Form): content=wtforms.StringField(validators=[Length(min=3,message="内容格式错误!")]) question_id=wtforms.IntegerField(validators=[InputRequired(message="问题id不能为空")])
#qa.py from flask import Blueprint,request,render_template,g,redirect,url_for from .forms import QuestionForm,AnswerForm from models import QuestionModel,AnswerModel from exts import db from decorators import login_required bp=Blueprint("qa",__name__,url_prefix="/") @bp.route("/") def index(): questions=QuestionModel.query.order_by(QuestionModel.create_time.desc()).all() return render_template("index.html",questions=questions) @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() return redirect("/") else: print(form.errors) return redirect(url_for("qa.public_question")) @bp.route("/qa/detail/<qa_id>") def qa_detail(qa_id): question=QuestionModel.query.get(qa_id) return render_template("detail.html",question=question) # @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")))
主要是前端代码的修改,主要是完善上一个步骤
#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)
完结!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。