文章目录
1. 项目预览1.1 登录1.2 注册2. 项目目录结构3. 项目代码展示blueprint__init__.pyforms.pyuser.pystaticbootstrap@4.6.min.cssjquery.3.6.min.jsregister.jstemplatesbase.htmlindex.htmllogin.htmlregister.htmlapp.pyconfig.pydecorators.pyexts.pymodels.py1. 项目预览
1.1 登录
1.2 注册
2. 项目目录结构
3. 项目代码展示
blueprint
init.py
from .user import bp as user_bp
forms.py
import wtformsfrom wtforms.validators import length, email, EqualTofrom models import EmailCaptchaModel, UserModelclass 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)])password_confirm = wtforms.StringField(validators=[EqualTo("password")])def validate_captcha(self, field):captcha = field.dataemail = self.email.datacaptcha_model = EmailCaptchaModel.query.filter_by(email=email).first()if captcha_model.captcha.lower() != captcha.lower():raise wtforms.ValidationError("邮箱验证码错误!")def validate_email(self, field):email = field.datauser_model = UserModel.query.filter_by(email=email).first()if user_model:raise wtforms.ValidationError("邮箱已经存在!")
user.py
from flask import Blueprint, render_template, request, redirect, url_for, jsonify, session, flashfrom exts import mail, dbfrom flask_mail import Messagefrom models import EmailCaptchaModel, UserModelfrom datetime import datetimefrom .forms import RegisterForm, LoginFormfrom werkzeug.security import generate_password_hash, check_password_hashimport randomimport stringbp = Blueprint("user", __name__)@bp.route("/")def index():return render_template("index.html")@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.datapassword = form.password.datauser = UserModel.query.filter_by(email=email).first()if user and check_password_hash(user.password, password):session['user_id'] = user.idreturn 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.datausername = form.username.datapassword = form.password.data# md5hash_password = generate_password_hash(password)user = UserModel(email=email, username=username, password=hash_password)db.session.add(user)mit()return redirect(url_for("user.login"))else:return redirect(url_for("user.register"))@bp.route("/logout")def logout():session.clear()return redirect(url_for('user.login'))@bp.route("/captcha", methods=['POST'])def get_captcha():# GET,POSTemail = request.form.get("email")letters = string.ascii_letters + string.digitscaptcha = "".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 = captchacaptcha_model.create_time = datetime.now()mit()else:captcha_model = EmailCaptchaModel(email=email, captcha=captcha)db.session.add(captcha_model)mit()print("captcha:", captcha)return jsonify({"code": 200})else:return jsonify({"code": 400, "message": "请先传递邮箱!"})
static
bootstrap@4.6.min.css
点击下载css代码
jquery.3.6.min.js
点击下载jquery代码
register.js
function bindCaptchaBtnClick(){$("#captcha-btn").on("click",function (event){var $this = $(this);var email = $("input[name='email']").val()if(!email){alert("请先输入邮箱");return;}$.ajax({url: "/user/captcha",method: "POST",data: {"email": email},success: function (res){var code = res['code'];if (code == 200){$this.off("click")var countDown = 60;var timer = setInterval(function (){countDown -= 1;if (countDown > 0){$this.text(countDown+"秒后重新发送");}else {$this.text("获取验证码");bindCaptchaBtnClick();clearInterval(timer);}},1000)alert("验证码发送成功!");}else{alert(res['message']);}}})});}$(function (){bindCaptchaBtnClick();});
templates
base.html
<!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.min.css') }}"><link rel="stylesheet" href="{{ url_for('static',filename='css/css.css') }}">{% block head %}{% endblock %}</head><body><nav class="navbar navbar-expand-lg navbar-light bg-light"><div class="container"><a class="navbar-brand" href="/"><svg t="1659145665644" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="/2000/svg" p-id="6166" width="50" height="50"><path d="M512 512m-405.333333 0a405.333333 405.333333 0 1 0 810.666666 0 405.333333 405.333333 0 1 0-810.666666 0Z" fill="#4CAF50" p-id="6167"></path><path d="M640 426.666667c47.061333 0 85.333333 38.272 85.333333 85.333333s-38.272 85.333333-85.333333 85.333333-85.333333-38.272-85.333333-85.333333 38.272-85.333333 85.333333-85.333333m0-85.333334a170.666667 170.666667 0 1 0 0 341.333334 170.666667 170.666667 0 0 0 0-341.333334z" fill="#FFFFFF" p-id="6168"></path><path d="M384 426.666667c47.061333 0 85.333333 38.272 85.333333 85.333333s-38.272 85.333333-85.333333 85.333333-85.333333-38.272-85.333333-85.333333 38.272-85.333333 85.333333-85.333333m0-85.333334a170.666667 170.666667 0 1 0 0 341.333334 170.666667 170.666667 0 0 0 0-341.333334z" fill="#FFFFFF" p-id="6169"></path></svg></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></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>
index.html
{% extends "base.html" %}{% block title %}首页{% endblock %}{% block head %}{% endblock %}{% block body %}<h1>文章首页</h1>{% endblock %}
login.html
{% extends "base.html" %}{% block title %}登录{% endblock %}{% block head %}{% endblock %}{% block body %}<div class="row mt-4"><div class="col"></div><div class="col"><form action="{{ url_for("user.login") }}" method="post"><div class="form-group"><label for="exampleInputEmail1">邮箱</label><input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" name="email"></div><div class="form-group"><label for="exampleInputPassword1">密码</label><input type="password" name="password" class="form-control" id="exampleInputPassword1"></div>{% for message in get_flashed_messages() %}<div class="from-group"><div class="text-danger">{{message }}</div></div>{% endfor %}<div class="from-group"><button type="submit" class="btn btn-primary btn-block">立即登录</button></div></form></div><div class="col"></div></div>{% endblock %}
register.html
{% extends "base.html" %}{% block title %}注册{% endblock %}{% block head %}<script src="{{ url_for('static',filename='jquery/jquery.3.6.min.js') }}"></script><script src="{{ url_for('static',filename='js/register.js') }}"></script>{% endblock %}{% block body %}<div class="row mt-4"><div class="col"></div><div class="col"><form action="{{ url_for("user.register") }}" method="post"><div class="form-group"><label for="exampleInputEmail1">邮箱</label><input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"name="email"><small id="emailHelp" class="form-text text-muted">我们不会把邮箱用于其他用途</small></div><div class="form-group"><label for="exampleInputEmail1">验证码</label><div class="input-group"><input type="text" class="form-control" name="captcha"><div class="input-group-append"><button class="btn btn-outline-secondary" type="button" id="captcha-btn">获取验证码</button></div></div></div><div class="form-group"><label for="exampleInputEmail1">用户名</label><input type="text" class="form-control" name="username"></div><div class="form-group"><label for="exampleInputPassword1">密码</label><input type="password" class="form-control" id="exampleInputPassword1" name="password"></div><div class="form-group"><label for="exampleInputPassword1">确认密码</label><input type="password" class="form-control" name="password_confirm"></div><button type="submit" class="btn btn-primary btn-block">立即注册</button></form></div><div class="col"></div></div>{% endblock %}
app.py
from flask import Flask, session, gimport configfrom exts import db, mailfrom blueprints import user_bpfrom flask_migrate import Migratefrom models import UserModelapp = Flask(__name__)app.config.from_object(config)db.init_app(app)mail.init_app(app)migrate = Migrate(app, db)app.register_blueprint(user_bp)@app.before_requestdef before_request():user_id = session.get("user_id")if user_id:try:user = UserModel.query.get(user_id)g.user = userexcept:g.user = None@app.context_processordef context_processor():if hasattr(g, "user"):return {"user": g.user}else:return {}if __name__ == '__main__':app.run()
config.py
# 数据库配置信息HOSTNAME = '127.0.0.1' # 数据库地址PORT = '3306' # 端口默认:3306DATABASE = '数据库名'USERNAME = '数据库账号'PASSWORD = '数据库密码'DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)SQLALCHEMY_DATABASE_URI = DB_URISQLALCHEMY_TRACK_MODIFICATIONS = TrueSECRET_KEY = "sdasd54as56d4a65s4"# 邮箱配置MAIL_SERVER = ""MAIL_PORT = 465MAIL_USE_TLS = FalseMAIL_USE_SSL = TrueMAIL_DEBUG = TrueMAIL_USERNAME = "发件邮箱"MAIL_PASSWORD = "授权码"MAIL_DEFAULT_SENDER = "默认发件邮箱"
decorators.py
from flask import g, redirect, url_forfrom functools import wrapsdef 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
exts.py
from flask_sqlalchemy import SQLAlchemyfrom flask_mail import Maildb = SQLAlchemy()mail = Mail()
models.py
from exts import dbfrom datetime import datetimeclass 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)creat_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)